Compare commits

...

284 Commits

Author SHA1 Message Date
MaineK00n
3605645ff6 feat: init nightly vuls for blackhat 2022-11-15 11:26:26 +09:00
Kota Kanbe
1d97e91341 fix(libscan): delete map that keeps all file contents detected by FindLock to save memory (#1556)
* fix(libscan): delete Map that keeps all files detected by FindLock to save memory

* continue analyzing libs if err occurred

* FindLockDirs

* fix

* fix
2022-11-10 10:19:15 +09:00
MaineK00n
96333f38c9 chore(ubuntu): set Ubuntu 22.10 EOL (#1552) 2022-11-01 14:00:56 +09:00
MaineK00n
8b5d1c8e92 feat(cwe, cti): update dictionary (#1553)
* feat(cwe): update CWE dictionary

* feat(cti): update CTI dictionary

* fix(cwe): fix typo
2022-11-01 14:00:23 +09:00
MaineK00n
dea80f860c feat(report): add cyclonedx format (#1543) 2022-11-01 13:58:31 +09:00
dependabot[bot]
6eb4c5a5fe chore(deps): bump github.com/aquasecurity/trivy from 0.31.3 to 0.32.1 (#1538)
* chore(deps): bump github.com/aquasecurity/trivy from 0.31.3 to 0.32.1

Bumps [github.com/aquasecurity/trivy](https://github.com/aquasecurity/trivy) from 0.31.3 to 0.32.1.
- [Release notes](https://github.com/aquasecurity/trivy/releases)
- [Changelog](https://github.com/aquasecurity/trivy/blob/main/goreleaser.yml)
- [Commits](https://github.com/aquasecurity/trivy/compare/v0.31.3...v0.32.1)

---
updated-dependencies:
- dependency-name: github.com/aquasecurity/trivy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(deps): bump github.com/aquasecurity/trivy 0.32.1 to 0.33.0

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MaineK00n <mainek00n.1229@gmail.com>
2022-10-27 01:24:06 +09:00
Kota Kanbe
b219a8495e fix(cpescan): match if affected version is NA (#1548)
https://github.com/vulsio/go-cve-dictionary/pull/283
2022-10-19 16:57:32 +09:00
Kota Kanbe
eb87d5d4e1 fix(saas): panic: runtime error: comparing uncomparable type config.PortScanConf (#1537) 2022-10-04 11:55:48 +09:00
tomofumi0003
6963442a5e fix(report): send report to each slack channel (#1530)
* fix send report to each slack channel

* fix(report): use w.Cnf.Channel instead of channel

Co-authored-by: MaineK00n <mainek00n.1229@gmail.com>
2022-09-29 16:08:36 +09:00
Kota Kanbe
f7299b9dba fix(scan): detect AL2 even when empty /etc/redhat-release (#1536) 2022-09-29 11:12:30 +09:00
Satoru Nihei
379fc8a1a1 fix: fix query (#1534) 2022-09-28 20:51:20 +09:00
MaineK00n
947fbbb29e fix(ms): always sets isPkgCvesDetactable to true (#1492) 2022-09-07 12:05:16 +09:00
MaineK00n
06d2032c9c docs: update slack invite URL (#1524) 2022-09-07 12:04:28 +09:00
dependabot[bot]
d055c48827 chore(deps): bump github.com/aquasecurity/trivy from 0.30.4 to 0.31.3 (#1526)
Bumps [github.com/aquasecurity/trivy](https://github.com/aquasecurity/trivy) from 0.30.4 to 0.31.3.
- [Release notes](https://github.com/aquasecurity/trivy/releases)
- [Changelog](https://github.com/aquasecurity/trivy/blob/main/goreleaser.yml)
- [Commits](https://github.com/aquasecurity/trivy/compare/v0.30.4...v0.31.3)

---
updated-dependencies:
- dependency-name: github.com/aquasecurity/trivy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-07 12:02:08 +09:00
MaineK00n
2a00339da1 fix(lockfiles): fix privileges in lockfile scan (#1512)
* fix(lockfiles): fix privileges in lockfile scan

* style(fmt): add space in comment line
2022-09-02 18:18:00 +09:00
kidokidofire
2d959b3af8 Fix func to get EC2 instance ID by IMDSv2. (#1522)
Co-authored-by: kido3160 <s.kido.fy@future.co.jp>
2022-08-25 14:31:48 +09:00
kidokidofire
595e26db41 Enable to get EC2 instance ID by IMDSv2. (#1520)
Co-authored-by: kido3160 <s.kido.fy@future.co.jp>
2022-08-24 17:39:45 +09:00
Kota Kanbe
1e457320c5 chore: bump up version (#1511) 2022-08-08 16:55:31 +09:00
MaineK00n
a06e689502 feat(cwe): add cwe top25 2022 (#1504) 2022-08-04 18:00:45 +09:00
MaineK00n
ca3f6b1dbf feat(amazon): support Amazon Linux 2 Extra Repository (#1510)
* feat(amazon): support Amazon Linux 2 Extra Repository

* feat(amazon): set Amazon Linux EOL

* feat(oracle): set Oracle Linux EOL
2022-08-04 17:52:42 +09:00
dependabot[bot]
f1c78e42a2 chore(deps): bump github.com/aquasecurity/trivy from 0.30.3 to 0.30.4 (#1507)
Bumps [github.com/aquasecurity/trivy](https://github.com/aquasecurity/trivy) from 0.30.3 to 0.30.4.
- [Release notes](https://github.com/aquasecurity/trivy/releases)
- [Changelog](https://github.com/aquasecurity/trivy/blob/main/goreleaser.yml)
- [Commits](https://github.com/aquasecurity/trivy/compare/v0.30.3...v0.30.4)

---
updated-dependencies:
- dependency-name: github.com/aquasecurity/trivy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-03 09:53:08 +09:00
MaineK00n
2f3b8bf3cc chore(rocky): set Rocky Linux 9 EOL (#1495) 2022-07-27 02:48:10 +09:00
MaineK00n
ab54266f9e fix(library): fill libraryFixedIns{}.key in ftypes.Pnpm and ftypes.DotNetCore (#1498)
* fix(library): fill key in ftypes.Pnpm and ftypes.DotNetCore

* chore(library): change the data structure of LibraryMap
2022-07-26 13:53:50 +09:00
dependabot[bot]
d79d138440 chore(deps): bump github.com/aquasecurity/trivy from 0.30.2 to 0.30.3 (#1499)
Bumps [github.com/aquasecurity/trivy](https://github.com/aquasecurity/trivy) from 0.30.2 to 0.30.3.
- [Release notes](https://github.com/aquasecurity/trivy/releases)
- [Changelog](https://github.com/aquasecurity/trivy/blob/main/goreleaser.yml)
- [Commits](https://github.com/aquasecurity/trivy/compare/v0.30.2...v0.30.3)

---
updated-dependencies:
- dependency-name: github.com/aquasecurity/trivy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-26 04:52:32 +09:00
dependabot[bot]
139f3a81b6 chore(deps): bump github.com/aquasecurity/trivy from 0.27.1 to 0.30.0 (#1494)
* chore(deps): bump github.com/aquasecurity/trivy from 0.27.1 to 0.30.0

Bumps [github.com/aquasecurity/trivy](https://github.com/aquasecurity/trivy) from 0.27.1 to 0.30.0.
- [Release notes](https://github.com/aquasecurity/trivy/releases)
- [Changelog](https://github.com/aquasecurity/trivy/blob/main/goreleaser.yml)
- [Commits](https://github.com/aquasecurity/trivy/compare/v0.27.1...v0.30.0)

---
updated-dependencies:
- dependency-name: github.com/aquasecurity/trivy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(deps): bump github.com/aquasecurity/trivy from 0.30.0 to 0.30.2

* fix(library): change fanal to trivy/pkg/fanal

* chore: update integration

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MaineK00n <mainek00n.1229@gmail.com>
2022-07-25 16:47:57 +09:00
MaineK00n
d1a617cfff fix(ms): remove duplicate advisories (#1490) 2022-07-14 09:26:30 +09:00
MaineK00n
48f7597bcf feat(ms): import gost:MaineK00n/new-windows (#1481)
* feat(ms): import gost:MaineK00n/new-windows

* chore(discover): add CTI section

* feat(ms): fill KB with VulnInfo.DistroAdvisories instead of CveContent.Optional

* fix(ms): Change bitSize from 32 to 64

* fix(ms): delete KB prefix

* chore(ms): change logger

* fix(ms): fill in correct AdvisoryID

Co-authored-by: Sadayuki Matsuno <sadayuki.matsuno@gmail.com>
2022-07-04 14:26:41 +09:00
sadayuki-matsuno
93731311a1 feat(saas) add vuls tags from env (#1487) 2022-07-04 12:00:02 +09:00
MaineK00n
999529a05b feat(scanner): detect host key change (#1406)
* feat(scanner): detect host key change

* chore(scanner): add testcase
2022-07-04 10:57:43 +09:00
MaineK00n
847d820af7 feat(os): support Alpine Linux 3.16 (#1479) 2022-06-15 17:08:40 +09:00
MaineK00n
5234306ded feat(cti): add Cyber Threat Intelligence info (#1442)
* feat(cti): add Cyber Threat Intelligence info

* chore: replace io/ioutil as it is deprecated

* chore: remove --format-csv in stdout writer

* chore(deps): go get go-cti@v0.0.1

* feat(cti): update cti dict(support MITRE ATT&CK v11.1)

* chore(deps): go get go-cti@master
2022-06-15 17:08:12 +09:00
MaineK00n
86b60e1478 feat(config): support CIDR (#1415) 2022-06-10 18:24:25 +09:00
MaineK00n
42fdc08933 feat(os): support RHEL 9, CentOS Stream 9, Alma Linux 9 (#1465)
* feat(os): support RHEL 9

* feat(os): support CentOS Stream9, AlmaLinux 9
2022-06-09 06:39:16 +09:00
MaineK00n
38b1d622f6 feat(cwe): update CWE dictionary (#1443) 2022-06-09 06:36:54 +09:00
MaineK00n
2477f9a8f8 chore: tidy go.mod, add arm64 and workflows update (#1461)
* chore: tidy go.mod

* chore(gh): add arm64 and workflows update

* chore: disable staticcheck SA1019 for xerrors.Errorf

* chore: fix github.com/boltdb/bolt switch to github.com/etcd-io/bbolt? #1457
2022-06-09 06:10:07 +09:00
kurita0
ec6e90acd3 fix getting wp core version string via ssh (#1344)
* fix getting wp core version string via ssh

* check DocRoot
2022-06-09 06:05:15 +09:00
sadayuki-matsuno
2aca2e4352 feat(contrib/trivy) fill image info into scan results (#1475)
* feat(contrib/trivy) fill image info into scan results

* fix match size

* fix match size
2022-06-08 17:00:32 +09:00
sadayuki-matsuno
14518d925e fix(contriv/fvuls) initialize optional map (#1469) 2022-05-30 12:46:53 +09:00
sadayuki-matsuno
948f8c0751 add VULS_TAGS env into contiriv future-vuls (#1466) 2022-05-24 13:46:28 +09:00
sadayuki-matsuno
1c1e40058e feat(library) output library type when err (#1460) 2022-05-16 09:58:58 +09:00
Satoru Nihei
2158fc6cb1 fix: judge by scannedVia (#1456) 2022-05-06 09:38:38 +09:00
MaineK00n
91ed318c5d chore(deps): update trivy v0.27.1 (#1453)
* chore(deps): update trivy v0.27.1

* chore: add gosum
2022-04-27 15:43:23 +09:00
MaineK00n
bfc3828ce1 chore(deps): update goval-dictionary and gost (#1452) 2022-04-27 13:03:11 +09:00
dependabot[bot]
c7eac4e7fe chore(deps): bump github.com/aquasecurity/trivy from 0.25.4 to 0.27.0 (#1451)
* chore(deps): bump github.com/aquasecurity/trivy from 0.25.4 to 0.27.0

Bumps [github.com/aquasecurity/trivy](https://github.com/aquasecurity/trivy) from 0.25.4 to 0.27.0.
- [Release notes](https://github.com/aquasecurity/trivy/releases)
- [Changelog](https://github.com/aquasecurity/trivy/blob/main/goreleaser.yml)
- [Commits](https://github.com/aquasecurity/trivy/compare/v0.25.4...v0.27.0)

---
updated-dependencies:
- dependency-name: github.com/aquasecurity/trivy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(library): support go.mod scan

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MaineK00n <mainek00n.1229@gmail.com>
2022-04-27 12:46:47 +09:00
MaineK00n
cc63a0eccf feat(ubuntu): add Jammy Jellyfish(22.04) (#1431)
* feat(ubuntu): add Jammy Jellyfish(22.04)

* chore(deps): gost update

* chore(oval/ubuntu): fill kernel package name temporarily
2022-04-27 11:04:00 +09:00
Satoru Nihei
fd18df1dd4 feat: parse OS version from result of trivy-scan (#1444)
* chore(deps): bump github.com/aquasecurity/trivy from 0.24.2 to 0.25.4

Bumps [github.com/aquasecurity/trivy](https://github.com/aquasecurity/trivy) from 0.24.2 to 0.25.4.
- [Release notes](https://github.com/aquasecurity/trivy/releases)
- [Changelog](https://github.com/aquasecurity/trivy/blob/main/goreleaser.yml)
- [Commits](https://github.com/aquasecurity/trivy/compare/v0.24.2...v0.25.4)

---
updated-dependencies:
- dependency-name: github.com/aquasecurity/trivy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* test: add testcase

* feat: parse metadata

* refactor: change detect logic

* refactor: change parsing logic

* refactor: refactor check logic before detect

* fix: impl without reuseScannedCves

* feat: complement :latest tag

* Update contrib/trivy/parser/v2/parser.go

Co-authored-by: MaineK00n <mainek00n.1229@gmail.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MaineK00n <mainek00n.1229@gmail.com>
2022-04-27 10:28:20 +09:00
MaineK00n
8775b5efdf chore: fix lint error (#1438)
* chore: fix lint: revive error

* chore: golanci-lint uses go 1.18

* chore: refactor tasks in GNUmakefile

* chore: add trivy binary in fvuls image
2022-04-15 18:12:13 +09:00
dependabot[bot]
a9f29a6c5d chore(deps): bump github.com/aquasecurity/trivy from 0.24.2 to 0.25.1 (#1436)
* chore(deps): bump github.com/aquasecurity/trivy from 0.24.2 to 0.25.0

Bumps [github.com/aquasecurity/trivy](https://github.com/aquasecurity/trivy) from 0.24.2 to 0.25.0.
- [Release notes](https://github.com/aquasecurity/trivy/releases)
- [Changelog](https://github.com/aquasecurity/trivy/blob/main/goreleaser.yml)
- [Commits](https://github.com/aquasecurity/trivy/compare/v0.24.2...v0.25.0)

---
updated-dependencies:
- dependency-name: github.com/aquasecurity/trivy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(deps): bump up Go to 1.18 and trivy v0.25.1

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MaineK00n <mainek00n.1229@gmail.com>
2022-04-05 13:27:49 +09:00
Satoru Nihei
05fdde48f9 feat: support server scan for suse with text/plain (#1433) 2022-04-04 12:45:44 +09:00
MaineK00n
3dfbd6b616 chore(mod): update go-exploitdb module (#1428)
* chore(mod): update go-exploitdb module

* docs: add inthewild datasource

* Unique because URLs sometimes duplicate on GitHub and InTheWild

Co-authored-by: Kota Kanbe <kotakanbe@gmail.com>
2022-03-26 05:26:06 +09:00
MaineK00n
04f246cf8b chore: add fvuls image (#1426) 2022-03-25 06:17:33 +09:00
MaineK00n
7500f41655 chore(mod): update go-kev module (#1425) 2022-03-25 06:15:06 +09:00
MaineK00n
a1cc152e81 feat(library): add auto detect library (#1417) 2022-03-17 18:08:40 +09:00
Masato Yagi
1c77bc1ba3 feat: replace NVD-column with packages-column at output of report (#1414)
* replace NVD-col with packages-col

* fix typo

* set table row line
2022-03-17 17:14:41 +09:00
Satoru Nihei
ec31c54caf chore: update trivy from 0.23.0 to 0.24.02 (#1407)
* chore: update trivy from 0.23.0 to 0.24.2

* chore: deal with changing structs

see: 11f4f81123
2022-03-04 16:00:08 +09:00
Satoru Nihei
2f05864813 fix: handling when image contains no trivy-target (#1405)
* fix: handling when image contains no trivy-target

* refactor: use scanResult.Optional

* fix: add suppoted list to error message
2022-03-02 06:13:26 +09:00
Kota Kanbe
2fbc0a001e fix: nil pointer when no match for any OS (#1401)
* refactor: rename serverapi.go to scanner.go

* fix: nil pointer if no match for any OS
2022-02-24 07:58:29 +09:00
MaineK00n
7d8a24ee1a refactor(detector): standardize db.NewDB to db.CloseDB (#1380)
* feat(subcmds/report,server): read environment variables when configPath is ""

* refactor: standardize db.NewDB to db.CloseDB

* chore: clean up import

* chore: error wrap

* chore: update goval-dictionary

* fix(oval): return Pseudo instead of nil for client

* chore: fix comment

* fix: lint error
2022-02-19 09:20:45 +09:00
MaineK00n
7750347010 fix(oval/suse): use def.Advisory.Cves[0].CveID instead of def.Title (#1397) 2022-02-17 19:16:14 +09:00
MaineK00n
9bcffcd721 fix(configtest,scan): fix validateSSHConfig (#1395)
* fix(configtest,scan): support StrictHostKeyChecking no

* fix(configtest,scan): support ServerTypePseudo

* fix(configtest,scan): skip if using proxy
2022-02-17 08:15:23 +09:00
MaineK00n
787604de6a fix(suse): fix openSUSE, openSUSE Leap, SLES, SLED scan (#1384)
* fix(suse): fix openSUSE, openSUSE Leap scan

* docs: update README

* fix: unknown CveContent.Type

* fix: tui reporting

* fix: listening port was duplicated in format-full-text

* fix .gitignore

* fix: add EOL data for SLES12.5

Co-authored-by: Kota Kanbe <kotakanbe@gmail.com>
2022-02-15 17:11:54 +09:00
MaineK00n
5164fb1423 fix(util): Major() behavior for major version (#1393) 2022-02-15 07:59:29 +09:00
MaineK00n
07335617d3 fix(configtest,scan): support SSH config file (#1388)
* fix(configtest,scan): support SSH config file

* chore(subcmds): remove askKeyPassword flag
2022-02-12 21:50:56 +09:00
MaineK00n
e5855922c1 fix(redhat): detect RedHat version (#1387)
* fix(redhat): detect RedHat version

* fix err fmt string

Co-authored-by: Kota Kanbe <kotakanbe@gmail.com>
2022-02-12 20:09:51 +09:00
MaineK00n
671be3f2f7 feat(configtest,scan): detect known_hosts error (#1386) 2022-02-11 12:54:17 +09:00
MaineK00n
fe8d252c51 feat(debian): validate running kernel version (#1382)
* feat(debian): validate running kernel version

* chore(gost/debian): only stash when there is linux package
2022-02-11 12:36:48 +09:00
MaineK00n
0cdc7a3af5 chore(oval): update mod (#1385) 2022-02-09 10:20:07 +09:00
maito1201
1cfe155a3a feat(fedora): support fedora (#1367)
* feat(fedora): support fedora

* fix(fedora): fix modular package scan

* fix(fedora): check needs-restarting, oval arch, add source link

Co-authored-by: MaineK00n <mainek00n.1229@gmail.com>
2022-02-09 09:30:44 +09:00
MaineK00n
2923cbc645 fix(centos): identify CentOS and CentOS Stream (#1360) 2022-02-03 05:32:03 +09:00
MaineK00n
7c209cc9dc fix(gost): add nil check (#1379) 2022-02-03 05:25:11 +09:00
MaineK00n
84fa4ce432 feat(alpine): add Alpine 3.14, 3.15 EOL (#1359)
* feat(alpine): add Alpine 3.14, 3.15 EOL

* fix(alpine): change test case
2022-02-02 06:46:52 +09:00
MaineK00n
f2e9cd9668 fix(oval): fix query in PostgreSQL (#1372)
Co-authored-by: Kota Kanbe <kotakanbe@gmail.com>
2022-02-02 06:46:02 +09:00
Kota Kanbe
77049d6cbb feat(libscan): support trivy v0.23.0 (#1377)
* feat(libscan): support trivy v0.23.0

* fix lint err

* review
2022-02-01 10:40:16 +09:00
sadayuki-matsuno
b4c23c158b fix(scanner/base) export libFile fields (#1366) 2022-01-18 11:56:12 +09:00
sadayuki-matsuno
964b4aa389 fix(scanner/base) export libFile (#1365) 2022-01-18 11:31:36 +09:00
Kota Kanbe
dc5aa35db7 chore: update git submodule for integration test (#1364) 2022-01-18 10:22:00 +09:00
dependabot[bot]
43c05d06fc chore(deps): bump github.com/aquasecurity/trivy from 0.20.0 to 0.22.0 (#1350)
* chore(deps): bump github.com/aquasecurity/trivy from 0.20.0 to 0.22.0

Bumps [github.com/aquasecurity/trivy](https://github.com/aquasecurity/trivy) from 0.20.0 to 0.22.0.
- [Release notes](https://github.com/aquasecurity/trivy/releases)
- [Changelog](https://github.com/aquasecurity/trivy/blob/main/goreleaser.yml)
- [Commits](https://github.com/aquasecurity/trivy/compare/v0.20.0...v0.22.0)

---
updated-dependencies:
- dependency-name: github.com/aquasecurity/trivy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(library): trivy scan

* chore(integration): add lockfiles

* fix(library): support gobinary scan via trivy

* chore: add pom in IsTrivySupportedLib

* chore: fix LIBS

* fix(library): support trivy offline scan

* chore(integration): move vulsio/integration repository

* chore(integration): add integration as git submodule

* chore: update .gitignore

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MaineK00n <mainek00n.1229@gmail.com>
2022-01-18 08:27:11 +09:00
Kota Kanbe
a3f7d1d7e7 feat(go-kev): update go-kev deps (#1352) 2022-01-07 08:21:48 +09:00
Kota Kanbe
bb4a1ca6c2 GPLv3 (#1351) 2021-12-26 09:08:38 +09:00
Kota Kanbe
57cce640e1 Create SECURITY.md 2021-12-26 08:51:44 +09:00
kurita0
1eb5d36668 fix configtest stalled with scanMode=fast-root (#1339)
* fix configtest stalled with scanMode=fast-root

* repoquery does not require sudo privileges on centos
2021-12-26 08:31:11 +09:00
MaineK00n
6bc4850596 fix(detector/ospkg): Skip OVAL/gost search when the number of packages is 0 (#1343)
* fix(detector/ospkg): Skip OVAL/gost search when the number of packages is 0

* chore: easy refactoring
2021-12-26 07:53:18 +09:00
MaineK00n
24005ae7ae chore(GHActions): replace with dependabot (#1348)
* chore(GHActions): replace with dependabot

* chore(GHActions): remove tidy.yml due to deprecation
2021-12-26 07:48:11 +09:00
MaineK00n
7aa296bb57 fix(oval): fix RDB query (#1347) 2021-12-26 07:47:52 +09:00
Kota Kanbe
3829ed2f8e Fix the parsing logic of FreeBSD pkg-audit (#1334)
* fix scanUnsecurePackages for FreeBSD pkg audit output change

* Add test case TestParseBlock for FreeBSD pkg audit output change

* Fix for no CVE in a block

* fix(scan): parse logic of pkg-audit

* fix

ca761fb218

Co-authored-by: User Kurita <kurita@vuls0.digitiminimi.com>
2021-12-24 10:27:38 +09:00
MaineK00n
2b7294a504 feat(amazon): support amazon linux 2022 (#1338) 2021-12-09 11:06:44 +09:00
MaineK00n
0c6a892893 style: fix lint (#1335) 2021-11-19 15:46:51 +09:00
MaineK00n
89d94ad85a feat(detector): add known exploited vulnerabilities (#1331)
* feat(kevuln): add known exploited vulnerabilities

* chore: transfer repository owner

* feat: show CISA on top of CERT

* chore: rename var

* chore: rename var

* chore: fix review

* chore: fix message
2021-11-19 15:06:17 +09:00
sadayuki-matsuno
ffdb78962f update dictionaries (#1326) 2021-10-29 11:24:49 +09:00
Kota Kanbe
321dae37ce chore: update readme 2021-10-24 17:38:57 +09:00
Kota Kanbe
a31797af0b Merge branch 'sakura' 2021-10-24 17:33:48 +09:00
Kota Kanbe
32999cf432 chore: udpate readme 2021-10-24 17:32:35 +09:00
Kota Kanbe
88218f5d92 chore: update sponsor (#1325) 2021-10-24 17:25:03 +09:00
Kota Kanbe
15761933ac chore: update sponsor 2021-10-24 17:01:35 +09:00
Kota Kanbe
0b62842f0e chore: fix go-sqlite3 deps (#1324) 2021-10-20 12:33:59 +09:00
Kota Kanbe
6bceddeeda chore: update goval-dictionary (#1323)
* chore: update goval-dictionary

* fix errs
2021-10-20 11:10:33 +09:00
Kota Kanbe
2dcbff8cd5 chore: sponsor (#1321)
* fix readme

* chore: fix lint
2021-10-17 16:41:51 +09:00
Kota Kanbe
8659668177 fix(cpescan): bug in NvdVendorProductMatch (#1320)
* fix(cpescan): bug in NvdVendorProductMatch

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

* add v2 parser

* implement v2

* refactor

* feat: add show version to future-vuls

* add test case for v2

* trivy v0.20.0

* support --list-all-pkgs

* fix lint err

* add test case for jar

* add a test case for gemspec in container

* remove v1 parser and change Library struct

* Changed the field name in the model struct LibraryScanner

* add comment

* fix comment

* fix comment

* chore

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

* chore: rename

* go get -u go-exploitdb

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

* feat(go-msfdb): support http mode

* go get -u go-msfdb

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

* go get -u gost

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

* update gost

* chore: update gost

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

* chore: change linter from golint to revive

* chore(linter): set revive config

* chore: fix commands and update golangci-lint version

* fix: lint errs

* chore: update gost

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

* chore: fix lint err

* chore: set len of slice to 0

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

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

* feat(report): do not add duplicate CveContent

* chore: goval-dictionary update

* chore: go mod tidy

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

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

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

* fix(debian): fix test case
2021-09-08 10:47:34 +09:00
Kota Kanbe
3e67f04fe4 breaking-change(cpescan): Improve Cpe scan (#1290)
* chore(cpescan): enable to pass useJvn to detector.DetectCpeURIsCves()

* review comment

* chore: go mod update go-cve

* feat(cpescan): set JvnVendorProductMatch to confidence If detected by JVN

* add NvdExactVersionMatch andd NvdRoughVersionMatch

* add confidence-over option to report

* sort CveContetens

* fix integration-test
2021-09-07 16:18:59 +09:00
Kota Kanbe
b9416ae062 fix(report): too many SQL variables (#1296)
* fix(report): too many SQL variables

https://github.com/kotakanbe/go-cve-dictionary/pull/210

* fix lint err
2021-09-01 10:42:19 +09:00
otuki
b4e49e093e feat(GAdocker): Publish docker image with Github Actions (#1291)
* feat(GAdocker): publish docker image with Github Actions

* feat(master): publish Docker image with GHActions:

* feat(docker): publish docker image with GHAtions

* feat(master): remove unnecessary GHActions

* feat(master): remove unnecessary GHActions

* feat(master): Add user ID and password at Docker GHActions

* feat(master): Add user ID and password with docker/login
2021-09-01 08:44:55 +09:00
Kota Kanbe
020f6ac609 fix(scan): warning if err occurred while scanning ports (#1294)
[Aug 26 20:59:11] ERROR [localhost] Error on host, err: [Failed to scan Ports:
    github.com/future-architect/vuls/scanner.Scanner.getScanResults.func1
        /go/src/github.com/future-architect/vuls/scanner/serverapi.go:658
  - dial tcp 172.19.0.1:80: connect: no route to host]

Scan Summary
================
host    Error           Use configtest subcommand or scan with --debug to view the details

[Aug 26 20:59:11] ERROR [localhost] Failed to scan: Failed to scan. err:
    github.com/future-architect/vuls/scanner.Scanner.Scan
        /go/src/github.com/future-architect/vuls/scanner/serverapi.go:103
  - An error occurred on [host]
2021-08-27 06:20:50 +09:00
sadayuki-matsuno
7e71cbdd46 fix(gost) sort in ms converter (#1293) 2021-08-26 14:32:45 +09:00
Kota Kanbe
1003f62212 chore: update go-cve-dictionary (#1292) 2021-08-26 13:45:40 +09:00
Kota Kanbe
9b18e1f9f0 breaking-change(go-exploitdb): support new go-exploitdb (#1288) 2021-08-20 08:00:57 +09:00
Kota Kanbe
24f790f474 feat(go-cve): update go-cve-dictionary (#1287)
diff: a31a3152c1...5043255
2021-08-19 05:34:03 +09:00
MaineK00n
fb8749fc5e fix(cpescan): fix confidence in cpe uri scan (#1286)
* fix(cpescan): fix confidence in cpe uri scan

* feat(cpe): add NA case

* chore: use HasNvd, HasJvn instead of len

* chore: go-cve-dictionary update
2021-08-19 04:59:09 +09:00
MaineK00n
96c3592db1 breaking-change(go-cve-dict): support new go-cve-dictionary (#1277)
* feat(model): change CveContents(map[string]CveContent) to map[string][]CveContent

* fix(cpescan): use CveIDSource

* chore: check Nvd, Jvn data

* chore: go-cve-dictionary update

* chore: add to cveDetails as is, since CveID is embedded in the response
2021-08-13 18:00:55 +09:00
Kota Kanbe
d65421cf46 fix(cpescan): JVN scan False-Negative on RDB-backend (#1283)
https://github.com/kotakanbe/go-cve-dictionary/pull/199
2021-08-13 09:58:04 +09:00
Kota Kanbe
c52ba448cd chore: update readme (#1282) 2021-08-12 09:37:45 +09:00
Kota Kanbe
21adce463b update readme 2021-08-12 09:31:12 +09:00
MaineK00n
f24240bf90 feat(library): update trivy v0.19.2 (#1278) 2021-08-02 05:40:57 +09:00
kazuminn
ff83cadd6e feat(os) : support Alma Linux (#1261)
* support Alma Linux

* fix miss

* feat(os) : support Rocky linux  (#1260)

* support rocky linux scan

* fix miss

* lint

* fix : like #1266 and error Failed to parse CentOS

* pass make test

* fix miss

* fix pointed out with comment

* fix golangci-lint error
2021-08-02 04:36:43 +09:00
Phil
e8c09282d9 Update ubuntu.go (#1279)
URI correction for ubuntu; see gost project: https://github.com/knqyf263/gost/blob/master/server/server.go#L48
2021-08-02 04:25:51 +09:00
Kota Kanbe
5f4d68cde4 feat(go-msf): update deps (#1275)
https://github.com/takuzoo3868/go-msfdb/pull/22
2021-07-21 09:13:34 +09:00
Kota Kanbe
9077a83ea8 fix(docker): docker build error (#1274) 2021-07-20 05:31:05 +09:00
Kota Kanbe
543dc99ecd fix(cpescan): CpeVendorProductMatch not set when Redis Backend (#1273)
* fix(cpescan): CpeVendorProductMatch not set when Redis Backend

* fix(integration): deprecated CPE URI

* fix(integration-test): add a test case for CpeVendorProductMatch

* fix review

* update deps go-cve-dict v0.6.2
2021-07-19 08:43:58 +09:00
Kota Kanbe
f0b3a8b1db feat(cpescan): Use JVN as a second DB for CPE scan (#1268)
* feat(cpescan): Use JVN as a second DB for CPE scan

* feat(tui): display score of detectionmethod

* update go.mod
2021-07-08 12:39:46 +09:00
Norihiro NAKAOKA
0b9ec05181 Support scanning Ubuntu using Gost (#1243)
* chore: add vuls binary in gitignore

* feat(gost): support ubuntu

* chore(debian): fix typo

* feat(ubuntu): more detail on CveContent

* chore: update .gitignore

* chore: update gost deps

* feat(ubuntu): add test in gost/ubuntu

* chore: fix typo

* Revert "chore: fix typo"

This reverts commit 9f2f1db233.

* docs: update README
2021-07-08 08:31:46 +09:00
Norihiro NAKAOKA
0bf12412d6 fix(rocky): fix Scan in Rocky Linux (#1266)
* fix(rocky): fix OVAL scan in Rocky Linux

* chore: add FreeBSD13 EOL, fix #1245

* chore(rocky): add Rocky Linux EOL tests

* feat(rocky): implement with reference to CentOS

* feat(raspbian): add Raspbian to Server mode

* feat(rocky): support gost scan

* fix(rocky): rocky support lessThan

* chore: update doc and comment
2021-07-08 05:39:48 +09:00
Peter Sedgewick
0ea4d58c63 fix(gost): Use DBDriver ctx in Psuedo (#1264) 2021-07-02 06:18:44 +09:00
kazuminn
5755b00576 feat(os) : support Rocky linux (#1260)
* support rocky linux scan

* fix miss

* lint
2021-07-02 05:35:47 +09:00
Shigechika AIKAWA
1c8e074c9d Feat report googlechat (#1257) (#1258)
* feat: Support Ubuntu21

* feat(report): Send report via Google Chat

* feat(report): Send report via Google Chat

* Snip too long message as (The rest is omitted).

* sorry for mixed feat-ubuntu21 branch. exlucded it

* append diff, attack vector and exploits info

* add ServerName filter by regexp

* rename variables and rewrite validators

* fix renaming miss

* fix renaming miss, again
2021-07-02 05:32:00 +09:00
Shigechika AIKAWA
0e0e5ce4be feat: Support Ubuntu21 (#1231) 2021-06-28 10:28:54 +09:00
Kota Kanbe
23dfe53885 chore: update go-exploitdb (#1262) 2021-06-28 08:29:16 +09:00
Norihiro NAKAOKA
8e6351a9e4 feat(oval): goval-dictionary update (#1259)
* feat(oval): err check for GetLastModified

* feat(oval): goval-dictionary update
2021-06-25 14:08:50 +09:00
Shigechika AIKAWA
3086e2760f fix Ubuntu 20.10 End of Life on July 22 2021 (#1256) 2021-06-23 08:14:38 +09:00
Norihiro NAKAOKA
b8db2e0b74 feat(report): Change the priority of CVE information in Debian (#1202)
* fix (bug) : using ScanResults refs #1019

* feat(gost): WIP change priority of CVE Info in Debian

* feat(report): change priority of CVE Info in Debian

* refactor: move RemoveRaspbianPackFromResult

* style: remove comment

* fix: lint error

* style: change coding style

* feat(report): support reporting with gost alone

* fix: merge error

* refactor(debian): change code to be simple
2021-06-21 15:14:41 +09:00
Kota Kanbe
43b46cb324 chore: add test data for integration test (#1254) 2021-06-17 14:01:10 +09:00
Kota Kanbe
d0559c7719 chore: update gost deps (#1253) 2021-06-16 18:45:48 +09:00
Kota Kanbe
231c63cf62 fix(libscan): support empty LibraryFixedIn (#1252) 2021-06-16 13:28:12 +09:00
Kota Kanbe
2a9aebe059 fix(report): improve cpe match logic (#1251)
* fix(report): improve cpe match logic

https://github.com/kotakanbe/go-cve-dictionary/pull/189

* fix vet error
2021-06-11 14:39:41 +09:00
Kota Kanbe
4e535d792f chore: fix build-tags in .goreleaser.yml (#1250) 2021-06-09 09:49:26 +09:00
Kota Kanbe
4b487503d4 chore: add go.sum test data for integration test (#1249)
* add go.sum test data for integration test

* chore: .gitignore
2021-06-09 09:18:32 +09:00
Kota Kanbe
0095c40e69 fix(vet): go vet err of make build-scanner (#1248) 2021-06-09 08:00:52 +09:00
Kota Kanbe
82c1abfd3a fix(report): detection logic bugs for Oracle Linux (#1247)
* fix(report): continue detecting if arch is emtpy for Oracle Linux

* fix test case

* fix(report): a bug of `Not Fixed Yet` of Oracle linux scanning
2021-06-09 05:46:42 +09:00
sadayuki-matsuno
40988401bd feat(scanner) separate func analize libraries (#1246)
* feat(scanner) separate func analize libraries

* fix(scanner) fix typo
2021-06-04 07:42:29 +09:00
Kota Kanbe
e8e3f4d138 feat(lib): support of Go (go.sum) scan (#1244)
* chore: update trivy deps

* fix(test): fix sort order in json

* parse go.sum in scanning

* feat(lib): support go.sum
2021-06-03 11:31:37 +09:00
Norihiro NAKAOKA
7eb77f5b51 feat(scan): support external port scanner(nmap) in host machine (#1207)
* feat(scan): load portscan settings from config.toml

* feat(scan): support external port scanner:nmap

* style: rename variable

* feat(scan): logging apply options

* feat(scan): remove spoof ip address option

* feat(scan): more validate port scan config

* style: change comment

* fix: parse port number as uint16

* feat(discover): add portscan section

* feat(discover): change default scanTechniques

* feat(docker): add nmap and version update

* feat(scan): nmap module upgrade

* fix: wrap err using %w

* feat(scan): print cmd using external port scanner

* feat(scan): more details external port scan command

* feat(scan): add capability check in validation

* fix(scanner): format error

* chore: change format
2021-05-26 09:35:28 +09:00
Kota Kanbe
e115235299 fix(test): dev mode to false in package-lock.json (#1242)
* fix(test): dev mode to false in package-lock.json

* fix: vet warning
2021-05-17 08:04:16 +09:00
otuki
151d4b2d30 fix(scan): Avoid panic when SSH connection refused (#1236)
* fix(fix-ssh-fata): Avoid panic when SSH connection refused

* chore(fix-ssh-fata): fix typo
2021-05-12 18:30:26 +09:00
Kota Kanbe
e553f8b4c5 feat(trivy): go mod update trivy v0.17.2 (#1235)
* feat(trivy): go mod update trivy v0.17.2

* wg.Wait

* fix reporting

* fix test case

* add gemfile.lock of redmine to integration test

* fix(test): add Pipfile.lock

* add poetry.lock to integration test

* add composer.lock to integration test

* add integration test case
2021-05-12 18:27:55 +09:00
Kota Kanbe
47652ef0fb fix(report): include the num of criticals in total #1233 (#1234) 2021-05-07 07:57:33 +09:00
Kota Kanbe
ab0e950800 fix(oracle): extracting only advisory ID from OVAL.title (#1232) 2021-04-29 12:54:36 +09:00
otuki
a7b0ce1c85 refactor(git-conf): config template in github section changed (#1229) 2021-04-28 14:53:11 +09:00
otuki
dc9c0edece refactor(git-conf): Specifing ignoreGitHubDismissed per repository (#1224)
* refactor(git-conf): Specifing ignoreGitHubDismissed per repository with config.toml

* refactor(git-conf): change json tag into camelCase

* refactor(git-conf): change first char of json tag into lowercase
2021-04-28 13:41:38 +09:00
Kota Kanbe
17ae386d1e chore: add a test case #1227 (#1228) 2021-04-28 12:18:18 +09:00
Kota Kanbe
2d369d0cfe Fix false positive for Oracle Linux (#1227)
* fix(oracle): false-positive(handle arch of pkgs)

* fix(oracle): false positive kernel-related CVEs

* add a test case for ksplice1

* fix(scan): handle uek kernel for Oracle linux

* fix(scan): hanlde uek kernel for reboot required

* fix(oracle): false-positive for redis-backend
2021-04-27 20:38:45 +09:00
Kota Kanbe
c36e645d9b fix(report): false positive for kernel-related CVE for RedHat, CentOS, Oracle and Amazon #1199 (#1223) 2021-04-23 08:59:46 +09:00
Kota Kanbe
40039c07e2 fix(report): panic when closing db connection of gost (#1222) 2021-04-23 06:14:12 +09:00
Kota Kanbe
a692cec0ef fix(gost): close gost DB connection in server mode #1217 (#1221) 2021-04-21 11:59:11 +09:00
otuki
e7ca491a94 fix(report): Avoid http reports error (#1216) 2021-04-21 10:00:58 +09:00
Shigechika AIKAWA
23f3e2fc11 fix(config): add Ubuntu 20.10 (#1218) 2021-04-21 09:05:33 +09:00
Kota Kanbe
27b3e17b79 feat(saas): delete json dir automatically after upload (#1212)
* feat(saas): delete json dir automatically after upload

* fix lint err
2021-04-15 05:58:41 +09:00
Kota Kanbe
740781af56 feat(logging): add -log-to-file and don't output to file by default (#1209)
* feat(logging): add -log-to-file and don't output to file by default

* update go-cve-dict

* fix lint err
2021-04-05 17:41:07 +09:00
Kota Kanbe
36c9c229b8 fix(report): avoid nil pointer when report FreeBSD (#1208) 2021-04-05 12:54:27 +09:00
Norihiro NAKAOKA
183fdcbdef fix: support for missing files in the results or results directory (#1206)
* fix: support for missing files in the results or results directory

* fix: support for missing files in the results or results directory
2021-04-05 07:28:20 +09:00
Kota Kanbe
a2a697900a refactor: move const to constant pkg (#1205) 2021-04-02 15:33:02 +09:00
Kota Kanbe
6fef4db8a0 fix .goreleaser.yml (#1204)
* fix .goreleaser.yml

* chore: fix lint warnings
2021-04-01 17:43:54 +09:00
sadayuki-matsuno
e879ff1e9e feat(scanner) export pkg list scan method (#1203)
* feat(scanner) export pkg list scan method

* fix args

* fix func

* fix init debian
2021-04-01 17:38:20 +09:00
Kota Kanbe
9bfe0627ae refactor: don't use global Config in private func (#1197)
* refactor: cve_client.go

* refactor: don't use global Config in private func

* remove import alias for config

* refactor: dbclient

* refactor: resultDir

* refactor: resultsDir

* refactor

* refactor: gost

* refactor: db client

* refactor: cveDB

* refactor: cvedb

* refactor: exploitDB

* refactor: remove detector/dbclient.go

* refactor: writer

* refactor: syslog writer

* refactor: ips

* refactor: ensureResultDir

* refactor: proxy

* fix(db): call CloseDB

* add integration test

* feat(report): sort array in json

* sort func for json diff

* add build-int to makefile

* add int-rds-redis to makefile

* fix: test case, makefile

* fix makefile

* show cve count after diff

* make diff

* diff -c

* sort exploits in json for diff

* sort metasploit, exploit
2021-04-01 13:36:24 +09:00
Tomoya Amachi
0179f4299a fix(trivy-to-vuls): converts even if null vulnerabilities (#1201) 2021-03-22 19:32:08 +09:00
Kota Kanbe
56017e57a0 feat(trivy): update trivy (#1196) 2021-03-12 09:31:48 +09:00
Kota Kanbe
cda91e0906 refactor: loading owasp dependency check xml (#1195) 2021-03-11 08:51:44 +09:00
Kota Kanbe
5d47adb5c9 fix(report): prioritize env vars over config.toml (#1194) 2021-03-10 07:39:58 +09:00
Kota Kanbe
54e73c2f54 fix(wordpress): enable to detect vulns of WordPress Core (#1193) 2021-03-09 10:40:52 +09:00
segatomo
2d075079f1 fix(log): remove log output of opening and migrating db (#1191)
* fix(log): remove log output of opening and migrating db

* fix(log): remove log output of opening and migrating db
2021-03-05 16:16:10 +09:00
Kota Kanbe
2a8ee4b22b refactor(report): azure and aws writer (#1190) 2021-03-04 07:42:38 +09:00
Kota Kanbe
1ec31d7be9 fix(configtest): all servers in the config if no args #1184 (#1189) 2021-03-03 12:51:07 +09:00
Kota Kanbe
02286b0c59 fix(scan): scan all servers in the config if no args #1184 (#1188) 2021-03-03 12:30:30 +09:00
Kota Kanbe
1d0c5dea9f fix(ubuntu): Fix deferred packages not showing as affected (#1187)
* fix(ubuntu): Fix deferred packages not showing as affected

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

* chore: Go version up
2021-03-02 07:50:35 +09:00
Kota Kanbe
1c4a12c4b7 refactor(report): initialize DB connection (#1186) 2021-03-02 06:34:46 +09:00
Kota Kanbe
3f2ac45d71 Refactor logger (#1185)
* refactor: logger

* refactor: logging

* refactor: rename func

* refactor: logging

* refactor: logging format
2021-02-26 10:36:58 +09:00
Kota Kanbe
518f4dc039 refactor: VulnDict (#1183) 2021-02-25 10:13:51 +09:00
Kota Kanbe
2cdeef4ffe refactor(config): validateOnReport (#1182) 2021-02-25 07:41:49 +09:00
Kota Kanbe
03579126fd refactor(config): localize config used like a global variable (#1179)
* refactor(report): LocalFileWriter

* refactor -format-json

* refacotr: -format-one-email

* refactor: -format-csv

* refactor: -gzip

* refactor: -format-full-text

* refactor: -format-one-line-text

* refactor: -format-list

* refacotr: remove -to-* from config

* refactor: IgnoreGitHubDismissed

* refactor: GitHub

* refactor: IgnoreUnsocred

* refactor: diff

* refacotr: lang

* refacotr: cacheDBPath

* refactor: Remove config references

* refactor: ScanResults

* refacotr: constant pkg

* chore: comment

* refactor: scanner

* refactor: scanner

* refactor: serverapi.go

* refactor: serverapi

* refactor: change pkg structure

* refactor: serverapi.go

* chore: remove emtpy file

* fix(scan): remove -ssh-native-insecure option

* fix(scan): remove the deprecated option `keypassword`
2021-02-25 05:54:17 +09:00
Kota Kanbe
e3c27e1817 fix(saas): Don't overwrite config.toml if UUID already set (#1180)
* fix(saas): Don't overwrite config.toml if UUID already set

* add a test case
2021-02-19 06:42:22 +09:00
Richard Alloway
aeaf308679 Add test-case to verify proper version comparison in lessThan() (#1178)
* Add test-case to verify proper version comparison when either/both/neither of newVer and ovalmodels.Package contain "_<minor version>"

* Rename vera to newVer in Test_lessThan()

* Fix oval/util_test.go formatting (make fmt)

Co-authored-by: Richard Alloway (OpenLogic) <ralloway@perforce.com>
2021-02-14 05:30:07 +09:00
Kota Kanbe
f5e47bea40 chore: add a test-case to #1176 (#1177) 2021-02-12 13:46:29 +09:00
Richard Alloway
50cf13a7f2 Pass packInOVAL.Version through centOSVersionToRHEL() to remove the "_<point release>" portion so that packInOVAL.Version strings like 1.8.23-10.el7_9.1 become 1.8.23-10.el7.1 (same behavior as newVer, which now allows packInOVAL.Version and newVer to be directly compared). (#1176)
Co-authored-by: Richard Alloway (OpenLogic) <ralloway@perforce.com>
2021-02-12 13:33:36 +09:00
Kota Kanbe
abd8041772 fix(scan): yum ps warning for Red Hat family (#1174)
* fix(yumps): no debug message for known patterns

* refactor(scan): yum-ps

* refacotr(scan): pkgPs
2021-02-12 13:03:06 +09:00
Kota Kanbe
847c6438e7 chore: fix debug message (#1169) 2021-02-11 06:31:51 +09:00
Kota Kanbe
ef8309df27 chore: remove the heck binary (#1173) 2021-02-11 06:31:32 +09:00
sadayuki-matsuno
0dff6cf983 fix(gost/microsoft) add workaround into mitigation (#1170)
* fix(gost/microsoft) add workaround into mitigation

* fix(gost/microsoft) fix typo and delete workaround field from vulninfo
2021-02-10 19:37:28 +09:00
kazuminn
4c04acbd9e feat(report) : Differences between vulnerability patched items (#1157)
* add plusDiff() and minusDiff()
* add plusDiff minusDiff test

Co-authored-by: Kota Kanbe <kotakanbe@gmail.com>
2021-02-10 06:55:48 +09:00
Kota Kanbe
1c4f231572 fix(scan): ignore rpm -qf exit status (#1168) 2021-02-09 17:26:12 +09:00
Kota Kanbe
51b8e169d2 fix(scan): warning if lsof command not found (#1167) 2021-02-07 07:28:45 +09:00
Kota Kanbe
b4611ae9b7 fix(scan): fix yum-ps warning Failed to exec which -bash (#1166) 2021-02-07 07:23:12 +09:00
Kota Kanbe
cd6722017b fix(scan): yum-ps err Failed to find the package (#1165) 2021-02-06 08:42:06 +09:00
Kota Kanbe
290edffccf fix(log): output version to log for debugging purpose (#1163) 2021-02-04 07:47:56 +09:00
Kota Kanbe
64a6222bf9 fix(report): set created_at and updated_at of trivy to json (#1162) 2021-02-03 17:52:44 +09:00
Kota Kanbe
adb686b7c9 fix(report): set created_at and updated_at of wpscan.com to json (#1161) 2021-02-03 16:41:44 +09:00
Kota Kanbe
d4af341b0f fix(report): remove duplicated refreshing logic when report with -diff (#1160) 2021-02-03 07:37:19 +09:00
Kota Kanbe
fea7e93c8d chore: fix comment (#1158) 2021-02-02 06:06:49 +09:00
sadayuki-matsuno
8b6b8d0f2e feat(wordpress): define API limit exceed error for wpscan.com (#1155)
* feat(wordpress) specify wp err

* fix typo, chagne const name

Co-authored-by: Kota Kanbe <kotakanbe@gmail.com>
2021-01-30 09:53:41 +09:00
Kota Kanbe
4dcbd865cc fix(report): set http timeout 10 sec (#1154)
* fix(report): set http timeout 10 sec

* fix: add an error handling
2021-01-30 09:40:33 +09:00
Kota Kanbe
39b19444fe Merge branch 'master' of github.com:future-architect/vuls 2021-01-28 16:24:14 +09:00
Kota Kanbe
644d5a5462 fix(report): remove retry logic for wpscan.com (#1151)
* fix(saas) change saas upload s3 key (#1116)

* fix(report): remove retry logic for wpscan.com

Co-authored-by: sadayuki-matsuno <sadayuki.matsuno@gmail.com>
2021-01-28 16:21:33 +09:00
Kota Kanbe
8e18451e3f Merge branch 'master' of github.com:future-architect/vuls 2021-01-28 08:24:23 +09:00
Kota Kanbe
3dbdd01f97 fix(report): wordrpess scanning skipped when package is emtpy (#1150) 2021-01-28 08:24:03 +09:00
sadayuki-matsuno
a89079c005 fix(saas) change saas upload s3 key (#1116) 2021-01-28 08:20:13 +09:00
sadayuki-matsuno
a8c0926b4f fix(saas) change saas upload s3 key (#1116) 2021-01-27 14:43:09 +09:00
Kota Kanbe
dd2959a31b fix(eol): add eol for alpine 3.13 (#1149) 2021-01-27 12:52:07 +09:00
Kota Kanbe
51099f42c3 fix(tui): runtime panic when tui with docker-base-setup (#1148)
* fix(tui): runtime panic when tui with docker-base-setup

* pass test case
2021-01-26 09:40:26 +09:00
Kota Kanbe
63f170cc7a fix(report): set severity in Red Hat OVAL to both CVSS v3 and v2 #1146 (#1147) 2021-01-26 07:58:59 +09:00
Kota Kanbe
3c1489e588 feat(report): range notion calc by severity when no-cvss-score (#1145) 2021-01-25 13:22:55 +09:00
Kota Kanbe
e4f1e03f62 feat(github): display GitHub Security Advisory details (#1143) 2021-01-24 09:15:04 +09:00
Kota Kanbe
83d48ec990 Create codeql-analysis.yml 2021-01-24 09:06:13 +09:00
Kota Kanbe
b20d2b2684 fix(scan): skip wordpress scan for preudo servers (#1142) 2021-01-21 07:11:55 +09:00
Kota Kanbe
2b918c70ae fix(scan): config dump nocolor in debug mode. (#1141) 2021-01-21 06:38:37 +09:00
Kota Kanbe
1100c133ba feat(config): Default values for WordPress scanning to be set in config.toml (#1140)
* chore: update go mod

* fix(wordpress): set default if defined in config.toml
2021-01-21 06:22:25 +09:00
Kota Kanbe
88899f0e89 refactor: around CheckHTTPHealth (#1139) 2021-01-20 07:41:29 +09:00
Kota Kanbe
59dc0059bc fix(model): omit changelog from json if empty (#1137) 2021-01-19 09:01:35 +09:00
Kota Kanbe
986fb304c0 fix(scan): add --nogpgcheck to dnf mod list to avoid Error: Cache-only enabled but no cache for *** (#1136) 2021-01-19 08:05:20 +09:00
Kota Kanbe
d6435d2885 fix(xml): remove -format-xml #1068 (#1134) 2021-01-18 04:38:00 +09:00
shopper
affb456499 fix(email.go):Fix runtime error(invalid memory address) (#1133) 2021-01-18 04:08:14 +09:00
Kota Kanbe
705ed0a0ac fix(discover): change config.toml template (#1132) 2021-01-16 07:58:46 +09:00
Kota Kanbe
dfffe5b508 fix(config): err occurs when host not set in local-scan-mode (#1129)
If host is not set in local scan mode, an error occurs.
2021-01-14 09:22:04 +09:00
Shigechika AIKAWA
fca102edba fix dnf prompt and ssh user (#1126) 2021-01-14 08:22:06 +09:00
Kota Kanbe
554b6345a2 chore: go mod update (#1127) 2021-01-14 08:12:47 +09:00
Kota Kanbe
aa954dc84c fix(scan): kindness msg when no-cache err on dnf mod list (#1128) 2021-01-14 08:12:35 +09:00
Kota Kanbe
b5506a1368 chore: go mod update (#1125) 2021-01-13 11:56:35 +09:00
Kota Kanbe
0b55f94828 Improve implementation around config (#1122)
* refactor config

* fix saas config

* feat(config): scanmodule for each server in config.toml

* feat(config): enable to specify containersOnly in config.toml

* add new keys of config.toml to discover.go

* fix summary output, logging
2021-01-13 08:46:27 +09:00
Kota Kanbe
a67052f48c fix(scan): err detecting EOL for alpine Linux (#1124) 2021-01-12 20:10:22 +09:00
Kota Kanbe
6eff6a9329 feat(report): display EOL information to scan summary (#1120)
* feat(report): display EOL information to scan summary

* detect Amazon linux EOL
2021-01-09 07:58:55 +09:00
Kota Kanbe
69d32d4511 feat(report): add a err code to wpscan.com API error (#1119) 2021-01-07 14:57:49 +09:00
Kota Kanbe
d7a613b710 chore: go mod update (#1118) 2021-01-07 08:02:29 +09:00
sadayuki-matsuno
669c019287 fix(cvecontent) Fixed not to split empty string (#1117) 2021-01-06 15:52:55 +09:00
Shigechika AIKAWA
fcc4901a10 fix(scan): Failed to parse CentOS Stream (#1098) 2021-01-06 14:57:19 +09:00
Kota Kanbe
4359503484 fix(redhat): possibility of false positives on RHEL (#1115) 2021-01-06 13:33:08 +09:00
Kota Kanbe
b13f93a2d3 feat(scan): support dnf modules (#1114)
* feat(scan): support dnf modules

* change dnf module list --installed to --enabled

* chore: refactor

* feat(report): detect logic for dnf modularity label

* fix func name

* chore: update go mods
2021-01-06 11:36:41 +09:00
Kota Kanbe
8405e0fad6 refactor(gost): Duplicate code into function (#1110)
* refactor(gost): Duplicate code into function

* fix
2020-12-30 08:33:30 +09:00
Kota Kanbe
aceb3f1826 fix(scan): add an error case for rpm -qa (#1109) 2020-12-30 08:05:14 +09:00
Kota Kanbe
a206675f3e fix(wordpress): remove cache because not permitted. (#1107) 2020-12-29 07:25:58 +09:00
Kota Kanbe
f4253d74ae fix(wordpress): wpscan.com unmarshal error (#1106)
* refactor(report): remove Integration.apply

* add an err check

* fix(wordpress): wpscan.com unmarshal error

* fix warnings
2020-12-29 07:11:04 +09:00
Kota Kanbe
aaea15e516 refactor(report): remove Integration.apply (#1105)
* refactor(report): remove Integration.apply

* add an err check
2020-12-29 06:59:48 +09:00
Kota Kanbe
83d1f80959 chore(report): remove stride and hipchat support (#1104) 2020-12-26 08:52:45 +09:00
Kota Kanbe
a33cff8f13 fix(reprot): use SQLite3 in current dir if not specified (#1103) 2020-12-26 08:24:17 +09:00
Kota Kanbe
8679759f60 chore: fix typo (#1102) 2020-12-26 08:23:02 +09:00
Kota Kanbe
53deaee3d7 refactor(config): remove DependencyCheckXMLPath in config.toml (#1100) 2020-12-25 06:38:00 +09:00
Kota Kanbe
5a14a58fe4 refactor(nvdxml): Remove codes related to NVD xml(deprecated) (#1099) 2020-12-25 06:16:14 +09:00
Kota Kanbe
fb1fbf8f95 feat(report): Add NVD as a source for mitigations, primarySrc URL and Patch URL (#1097)
* feat(report): Add NVD as a src for mitigations.

* feat(report): display "Vendor Advisory" URL in NVD

* feat(report): display patch urls in report, tui
2020-12-24 08:37:10 +09:00
Kota Kanbe
cfbf779f9b feat(exploit): add exploit link in NVD as a source (#1096)
Added Refs information with NVD's Expoit tag as an information source
for Exploit.
2020-12-16 07:10:18 +09:00
Kota Kanbe
d576b6c6c1 refactor(report): around FillCveInfo (#1095)
* refactor(report): around FillCveInfo

* refacotr(report): around FillCveInfo
2020-12-15 15:48:23 +09:00
Kota Kanbe
514eb71482 fix(server): make config loading same as scan (#1091)
* fix(server): make config loading same as scan

* also remove from report, tui
2020-12-15 04:33:14 +09:00
Kota Kanbe
43ed904db1 fix(deps): update dependencies (#1094)
* fix(dpes): update dependencies

* update go ver

* update go ver

* update go

* update go
2020-12-15 04:32:23 +09:00
Kota Kanbe
0a440ca629 fix(saas): add saas subcmd (#1093) 2020-12-11 16:19:36 +09:00
Kota Kanbe
eff1dbf95b feat(scanner): vuls-scanner binary on release archive (#1092) 2020-12-11 11:05:48 +09:00
Kota Kanbe
9a32a94806 refactor: fix build warnings (#1090) 2020-12-11 06:45:39 +09:00
Shigechika AIKAWA
2534098509 fix(report): wpvulndb poor versioning(#1088) (#1089) 2020-12-11 05:53:41 +09:00
sadayuki-matsuno
9497365758 update pkg (#1087) 2020-12-04 15:57:02 +09:00
Kota Kanbe
101c44c9c0 Change .goreleaser to build binaries for arm, 386, amd64 at release. (#1082)
* fix go-releaser

* add vuls-scanner
2020-11-28 06:39:52 +09:00
Kota Kanbe
ffd745c004 fix a compile error #1083 (#1084) 2020-11-27 15:14:04 +09:00
Kota Kanbe
5fea4eaef8 feat(nocgo): enable to build with CGO_ENABLED=0 (#1080) 2020-11-27 09:55:09 +09:00
Kota Kanbe
1f610043cf feat(scan): IgnoredJSONKyes to clear values in result json #1071 (#1078) 2020-11-20 10:36:36 +09:00
Kota Kanbe
3f8de02683 fix(portscan): to keep backward compatibility before v0.13.0 (#1076) 2020-11-19 16:54:36 +09:00
Kota Kanbe
d02535d053 fix(debian): false negative of kernel cves with rdb backend (#1075)
* fix(debian): false negative of kernel cves with rdb backend

* update golangci.yml

* add --timeout=10m to golangci.yml
2020-11-18 10:32:37 +09:00
Kota Kanbe
75fceff5f7 refactor(report): format-csv (#1072) 2020-11-05 21:10:35 +09:00
gy741
ebd3834a35 add(report) -format-csv option (#1034) 2020-11-05 20:56:19 +09:00
Kota Kanbe
93059b74c3 feat(report): IgnoredJSONKyes to clear values in result json (#1071)
* feat(report): IgnoredJSONKyes to clear values in result json

* fix(report): marshal indent in JSON everytime
2020-11-05 20:13:09 +09:00
Kota Kanbe
2fc3462d35 fix(libscan): update trivy deps (#1070) 2020-11-05 15:38:12 +09:00
Kota Kanbe
f78dab50cb fix(fast-root): affectedProcs, ports bug (#1067) 2020-10-31 14:21:11 +09:00
Norihiro NAKAOKA
edb324c3d9 fix(portscan): ignore loopback address on remote scan (#1062)
* change ignore loop back address on remote scan

* fix test case

* change append simple

* fix format

* set golangci-lint timeout

* Revert "set golangci-lint timeout"

This reverts commit 56b1c7089a.
2020-10-23 16:40:03 +09:00
Norihiro NAKAOKA
83bcca6e66 experimental: add smart(fast, minimum ports, silently) TCP port scanner (#1060)
* add struct ListenPorts

* change parse to models.ListenPorts from string

* change support models.ListenPorts in TUI

* add scanPort template , detectScanDest

* add Test_detectScanDest

* change impl scanPorts template

* fix build error

* change collect scan success address

* add Test_matchListenPorts

* add Test_updatePortStatus

* change display port scan result on tui

* change display scan emoji on report

* Revert "change display scan emoji on report"

This reverts commit e281882cc6.

* add continue

* change display format

* change no use loop label

* remove comment code

* change display

* fix padding

* change refactoring var , fn name

* fix var name

* fix var name

* change eye icon

* change icon

* delete unuse mod
2020-10-19 17:47:20 +09:00
Kota Kanbe
a124518d78 fix: hard-coded version #1057 (#1059) 2020-10-16 20:42:31 +09:00
Alexander Stein
94bf630e29 Expand negative grep match for any error for lib scans. (#1056)
Many thanks 👍 

Sure, that's better.

Note: FreeBSD
find: `find: /var/run/ppp: Permission denied`
2020-10-12 11:30:11 +09:00
shopper
31bb33fd90 ignore apk warning (#1052) 2020-10-12 10:40:01 +09:00
Kota Kanbe
4b680b9960 fix(scan-freebsd): also get installed with pkg info #1042 (#1051)
* fix(scan-freebsd): also get installed with `pkg info` #1042

* fix test
2020-09-12 05:08:41 +09:00
197 changed files with 6331 additions and 42215 deletions

View File

@@ -1,7 +0,0 @@
.dockerignore
Dockerfile
vendor/
cve.sqlite3*
oval.sqlite3*
setup/
img/

3
.github/FUNDING.yml vendored
View File

@@ -1,3 +0,0 @@
# These are supported funding model platforms
github: kotakanbe

View File

@@ -1,43 +0,0 @@
---
name: Bug Report
labels: bug
about: If something isn't working as expected.
---
# What did you do? (required. The issue will be **closed** when not provided.)
# What did you expect to happen?
# What happened instead?
* Current Output
Please re-run the command using ```-debug``` and provide the output below.
# Steps to reproduce the behaviour
# Configuration (**MUST** fill this out):
* Go version (`go version`):
* Go environment (`go env`):
* Vuls environment:
Hash : ____
To check the commit hash of HEAD
$ vuls -v
or
$ cd $GOPATH/src/github.com/future-architect/vuls
$ git rev-parse --short HEAD
* config.toml:
* command:

View File

@@ -1,9 +0,0 @@
---
name: Feature Request
labels: enhancement
about: I have a suggestion (and might want to implement myself)!
---
<!--
If this is a FEATURE REQUEST, request format does not matter!
-->

View File

@@ -1,10 +0,0 @@
---
name: Support Question
labels: question
about: If you have a question about Vuls.
---
<!--
If you have a trouble, feel free to ask.
Make sure you're not asking duplicate question by searching on the issues lists.
-->

View File

@@ -1,7 +0,0 @@
---
name: Vuls Repo
labels: vulsrepo
about: If something isn't working as expected.
---

View File

@@ -1,40 +0,0 @@
If this Pull Request is work in progress, Add a prefix of “[WIP]” in the title.
# What did you implement:
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context.
Fixes # (issue)
## Type of change
Please delete options that are not relevant.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update
# How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce.
# Checklist:
You don't have to satisfy all of the following.
- [ ] Write tests
- [ ] Write documentation
- [ ] Check that there aren't other open pull requests for the same issue/feature
- [ ] Format your source code by `make fmt`
- [ ] Pass the test by `make test`
- [ ] Provide verification config / commands
- [ ] Enable "Allow edits from maintainers" for this PR
- [ ] Update the messages below
***Is this ready for review?:*** NO
# Reference
* https://blog.github.com/2015-01-21-how-to-write-the-perfect-pull-request/

View File

@@ -1,28 +0,0 @@
name: golangci-lint
on:
push:
tags:
- v*
branches:
- master
pull_request:
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v1
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.26
# Optional: working directory, useful for monorepos
# working-directory: somedir
# Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0
# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true

View File

@@ -1,31 +0,0 @@
name: goreleaser
on:
push:
tags:
- '*'
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Unshallow
run: git fetch --prune --unshallow
-
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.14
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,21 +1,26 @@
name: Test
on: [pull_request]
on:
pull_request:
jobs:
build:
name: Build
test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v3
- name: Set up Go 1.x
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: 1.14.x
id: go
go-version-file: 'go.mod'
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Test
run: make test
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
args: --timeout=10m
- name: testing
run: go test -race ./...

View File

@@ -1,22 +0,0 @@
name: go-mod-tidy-pr
on:
schedule:
- cron: "0 0 * * 1" # Weekly build
jobs:
go-mod-tidy-pr:
name: go-mod-tidy-pr
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run go-mod-tidy-pr
uses: sue445/go-mod-tidy-pr@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
git_user_name: kotakanbe
git_user_email: kotakanbe@gmail.com
go_version: 1.14.x

40
.gitignore vendored
View File

@@ -1,18 +1,24 @@
vuls
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
.vscode
*.txt
*.json
*.sqlite3*
*.db
tags
.gitmodules
coverage.out
issues/
vendor/
log/
results/
*config.toml
!setup/docker/*
.DS_Store
dist/
.idea
# Vuls
vuls
!cmd/vuls
vuls.db
config.json
results

View File

@@ -1,17 +0,0 @@
name: golang-ci
linters-settings:
errcheck:
#exclude: /path/to/file.txt
linters:
disable-all: true
enable:
- goimports
- golint
- govet
- misspell
- errcheck
- staticcheck
- prealloc
- ineffassign

View File

@@ -1,70 +0,0 @@
project_name: vuls
env:
- GO111MODULE=on
release:
github:
owner: future-architect
name: vuls
builds:
- id: vuls
goos:
- linux
goarch:
- amd64
main: .
flags:
- -a
ldflags: -s -w -X main.version={{.Version}} -X main.revision={{.Commit}}
binary: vuls
- id: trivy-to-vuls
goos:
- linux
goarch:
- amd64
main: ./contrib/trivy/cmd/main.go
binary: trivy-to-vuls
- id: future-vuls
goos:
- linux
goarch:
- amd64
main: ./contrib/future-vuls/cmd/main.go
binary: future-vuls
archives:
- id: vuls
name_template: '{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
builds:
- vuls
format: tar.gz
files:
- LICENSE
- NOTICE
- README*
- CHANGELOG.md
- id: trivy-to-vuls
name_template: '{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
builds:
- trivy-to-vuls
format: tar.gz
files:
- LICENSE
- NOTICE
- README*
- CHANGELOG.md
- id: future-vuls
name_template: '{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
builds:
- future-vuls
format: tar.gz
files:
- LICENSE
- NOTICE
- README*
- CHANGELOG.md
snapshot:
name_template: SNAPSHOT-{{ .Commit }}

View File

@@ -1,514 +0,0 @@
# Change Log
## v0.4.1 and later, see [GitHub release](https://github.com/future-architect/vuls/releases)
## [v0.4.0](https://github.com/future-architect/vuls/tree/v0.4.0) (2017-08-25)
[Full Changelog](https://github.com/future-architect/vuls/compare/v0.3.0...v0.4.0)
**Implemented enhancements:**
- Output changelog in report, TUI and JSON for RHEL [\#367](https://github.com/future-architect/vuls/issues/367)
- Output changelog in report, TUI and JSON for Amazon Linux [\#366](https://github.com/future-architect/vuls/issues/366)
- Improve scanning accuracy by checking package versions [\#256](https://github.com/future-architect/vuls/issues/256)
- Improve SSH [\#415](https://github.com/future-architect/vuls/issues/415)
- Enable to scan even if target server can not connect to the Internet [\#258](https://github.com/future-architect/vuls/issues/258)
- SSH Hostkey check [\#417](https://github.com/future-architect/vuls/pull/417) ([kotakanbe](https://github.com/kotakanbe))
- v0.4.0 [\#449](https://github.com/future-architect/vuls/pull/449) ([kotakanbe](https://github.com/kotakanbe))
- Change default ssh method from go library to external command [\#416](https://github.com/future-architect/vuls/pull/416) ([kotakanbe](https://github.com/kotakanbe))
- Add containers-only option to configtest [\#411](https://github.com/future-architect/vuls/pull/411) ([knqyf263](https://github.com/knqyf263))
**Fixed bugs:**
- Running Vuls tui before vuls report does not show vulnerabilities checked by CPE [\#396](https://github.com/future-architect/vuls/issues/396)
- With a long package name, Local shell mode \(stty dont' work\) [\#444](https://github.com/future-architect/vuls/issues/444)
- Improve SSH [\#415](https://github.com/future-architect/vuls/issues/415)
- Report that a vulnerability exists in the wrong package [\#408](https://github.com/future-architect/vuls/issues/408)
- With a long package name, a parse error occurs. [\#391](https://github.com/future-architect/vuls/issues/391)
- Ubuntu failed to scan vulnerable packages [\#205](https://github.com/future-architect/vuls/issues/205)
- CVE-ID in changelog can't be picked up. [\#154](https://github.com/future-architect/vuls/issues/154)
- v0.4.0 [\#449](https://github.com/future-architect/vuls/pull/449) ([kotakanbe](https://github.com/kotakanbe))
- Fix SSH dial error [\#413](https://github.com/future-architect/vuls/pull/413) ([kotakanbe](https://github.com/kotakanbe))
- Update deps, Change deps tool from glide to dep [\#412](https://github.com/future-architect/vuls/pull/412) ([kotakanbe](https://github.com/kotakanbe))
- fix report option Loaded error-info [\#406](https://github.com/future-architect/vuls/pull/406) ([hogehogehugahuga](https://github.com/hogehogehugahuga))
- Add --user root to docker exec command [\#389](https://github.com/future-architect/vuls/pull/389) ([PaulFurtado](https://github.com/PaulFurtado))
**Closed issues:**
- README.md.ja not include "Oracle Linux, FreeBSD" [\#465](https://github.com/future-architect/vuls/issues/465)
- Can't scan remote server - \(centos 7 - updated\) [\#451](https://github.com/future-architect/vuls/issues/451)
- An abnormality in the result of vuls tui [\#439](https://github.com/future-architect/vuls/issues/439)
- compile faild [\#436](https://github.com/future-architect/vuls/issues/436)
- Can't install vuls on CentOS 7 [\#432](https://github.com/future-architect/vuls/issues/432)
- Vuls scan doesn't show severity score in any of the vulnerable packages [\#430](https://github.com/future-architect/vuls/issues/430)
- Load config failedtoml: cannot load TOML value of type string into a Go slice [\#429](https://github.com/future-architect/vuls/issues/429)
- vuls scan not running check-update with sudo for Centos 7 [\#428](https://github.com/future-architect/vuls/issues/428)
- options for configtest not being activated [\#422](https://github.com/future-architect/vuls/issues/422)
- "could not find project Gopkg.toml, use dep init to initiate a manifest" when installing vuls [\#420](https://github.com/future-architect/vuls/issues/420)
- go get not get [\#407](https://github.com/future-architect/vuls/issues/407)
- Failed to scan via docker. err: Unknown format [\#404](https://github.com/future-architect/vuls/issues/404)
- Failed to scan - kernel-xxx is an installed security update [\#403](https://github.com/future-architect/vuls/issues/403)
- 169.254.169.254 port 80: Connection refused [\#402](https://github.com/future-architect/vuls/issues/402)
- vuls scan --debug cause `invalid memory address` error [\#397](https://github.com/future-architect/vuls/issues/397)
- Provide a command line flag that will automatically install aptitude on debian? [\#390](https://github.com/future-architect/vuls/issues/390)
**Merged pull requests:**
- export fill cve info [\#467](https://github.com/future-architect/vuls/pull/467) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- add oval docker [\#466](https://github.com/future-architect/vuls/pull/466) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- fix typos in commands. [\#464](https://github.com/future-architect/vuls/pull/464) ([ymomoi](https://github.com/ymomoi))
- Update README [\#463](https://github.com/future-architect/vuls/pull/463) ([kotakanbe](https://github.com/kotakanbe))
- export FillWithOval [\#462](https://github.com/future-architect/vuls/pull/462) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- add serveruuid field [\#458](https://github.com/future-architect/vuls/pull/458) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- add s3 dirctory option [\#457](https://github.com/future-architect/vuls/pull/457) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- Extract Advisory.Description on RHEL, Amazon, Oracle [\#450](https://github.com/future-architect/vuls/pull/450) ([kotakanbe](https://github.com/kotakanbe))
- nosudo on CentOS and Fetch Changelogs on Amazon, RHEL [\#448](https://github.com/future-architect/vuls/pull/448) ([kotakanbe](https://github.com/kotakanbe))
- change logrus package to lowercase and update other packages [\#446](https://github.com/future-architect/vuls/pull/446) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- add db backend redis [\#445](https://github.com/future-architect/vuls/pull/445) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- fast test [\#435](https://github.com/future-architect/vuls/pull/435) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- fix typo [\#433](https://github.com/future-architect/vuls/pull/433) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- Add support for PostgreSQL as a DB storage back-end [\#431](https://github.com/future-architect/vuls/pull/431) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- typo README.js.md [\#426](https://github.com/future-architect/vuls/pull/426) ([ryurock](https://github.com/ryurock))
- Add TOC to README [\#425](https://github.com/future-architect/vuls/pull/425) ([kotakanbe](https://github.com/kotakanbe))
- Fixing \#420 where lock and manifest have moved to TOML [\#421](https://github.com/future-architect/vuls/pull/421) ([elfgoh](https://github.com/elfgoh))
- Define timeout for vulnerabilities scan and platform detection [\#414](https://github.com/future-architect/vuls/pull/414) ([s7anley](https://github.com/s7anley))
- Enable -timeout option when detecting OS [\#410](https://github.com/future-architect/vuls/pull/410) ([knqyf263](https://github.com/knqyf263))
- Remove duplicate command in README [\#401](https://github.com/future-architect/vuls/pull/401) ([knqyf263](https://github.com/knqyf263))
- Fix to read config.toml at tui [\#441](https://github.com/future-architect/vuls/pull/441) ([usiusi360](https://github.com/usiusi360))
- Change NVD URL to new one [\#419](https://github.com/future-architect/vuls/pull/419) ([kotakanbe](https://github.com/kotakanbe))
- Add some testcases [\#418](https://github.com/future-architect/vuls/pull/418) ([kotakanbe](https://github.com/kotakanbe))
## [v0.3.0](https://github.com/future-architect/vuls/tree/v0.3.0) (2017-03-24)
[Full Changelog](https://github.com/future-architect/vuls/compare/v0.2.0...v0.3.0)
**Implemented enhancements:**
- Changelog parsing fails when package maintainers aren't consistent regarding versions [\#327](https://github.com/future-architect/vuls/issues/327)
- Docker scan doesn't report image name [\#325](https://github.com/future-architect/vuls/issues/325)
- vuls report -to-email only one E-Mail [\#295](https://github.com/future-architect/vuls/issues/295)
- Support RHEL5 [\#286](https://github.com/future-architect/vuls/issues/286)
- Continue scanning even when some hosts have tech issues? [\#264](https://github.com/future-architect/vuls/issues/264)
- Normalization of JSON output [\#259](https://github.com/future-architect/vuls/issues/259)
- Add report subcommand, change scan subcommand options [\#239](https://github.com/future-architect/vuls/issues/239)
- scan localhost? [\#210](https://github.com/future-architect/vuls/issues/210)
- Can Vuls show details about updateable packages [\#341](https://github.com/future-architect/vuls/issues/341)
- Scan all containers except [\#285](https://github.com/future-architect/vuls/issues/285)
- Notify the difference from the previous scan result [\#255](https://github.com/future-architect/vuls/issues/255)
- EC2RoleCreds support? [\#250](https://github.com/future-architect/vuls/issues/250)
- Output confidence score of detection accuracy and detection method to JSON or Reporting [\#350](https://github.com/future-architect/vuls/pull/350) ([kotakanbe](https://github.com/kotakanbe))
- Avoid null slice being null in JSON [\#345](https://github.com/future-architect/vuls/pull/345) ([kotakanbe](https://github.com/kotakanbe))
- Add -format-one-email option [\#331](https://github.com/future-architect/vuls/pull/331) ([knqyf263](https://github.com/knqyf263))
- Support Raspbian [\#330](https://github.com/future-architect/vuls/pull/330) ([knqyf263](https://github.com/knqyf263))
- Add leniancy to the version matching for debian to account for versio… [\#328](https://github.com/future-architect/vuls/pull/328) ([jsulinski](https://github.com/jsulinski))
- Add image information for docker containers [\#326](https://github.com/future-architect/vuls/pull/326) ([jsulinski](https://github.com/jsulinski))
- Continue scanning even when some hosts have tech issues [\#309](https://github.com/future-architect/vuls/pull/309) ([kotakanbe](https://github.com/kotakanbe))
- Add -log-dir option [\#301](https://github.com/future-architect/vuls/pull/301) ([knqyf263](https://github.com/knqyf263))
- Use --assumeno option [\#300](https://github.com/future-architect/vuls/pull/300) ([knqyf263](https://github.com/knqyf263))
- Add local scan mode\(Scan without SSH when target server is localhost\) [\#291](https://github.com/future-architect/vuls/pull/291) ([kotakanbe](https://github.com/kotakanbe))
- Support RHEL5 [\#289](https://github.com/future-architect/vuls/pull/289) ([kotakanbe](https://github.com/kotakanbe))
- Add LXD support [\#288](https://github.com/future-architect/vuls/pull/288) ([jiazio](https://github.com/jiazio))
- Add timeout option to configtest [\#400](https://github.com/future-architect/vuls/pull/400) ([kotakanbe](https://github.com/kotakanbe))
- Notify the difference from the previous scan result [\#392](https://github.com/future-architect/vuls/pull/392) ([knqyf263](https://github.com/knqyf263))
- Add Oracle Linux support [\#386](https://github.com/future-architect/vuls/pull/386) ([Djelibeybi](https://github.com/Djelibeybi))
- Change container scan format in config.toml [\#381](https://github.com/future-architect/vuls/pull/381) ([kotakanbe](https://github.com/kotakanbe))
- Obsolete CentOS5 support [\#378](https://github.com/future-architect/vuls/pull/378) ([kotakanbe](https://github.com/kotakanbe))
- Deprecate prepare subcommand to minimize the root authority defined by /etc/sudoers [\#375](https://github.com/future-architect/vuls/pull/375) ([kotakanbe](https://github.com/kotakanbe))
- Support IAM role for report to S3. [\#370](https://github.com/future-architect/vuls/pull/370) ([ohsawa0515](https://github.com/ohsawa0515))
- Add .travis.yml [\#363](https://github.com/future-architect/vuls/pull/363) ([knqyf263](https://github.com/knqyf263))
- Output changelog in report, TUI and JSON for Ubuntu/Debian/CentOS [\#356](https://github.com/future-architect/vuls/pull/356) ([kotakanbe](https://github.com/kotakanbe))
**Fixed bugs:**
- Debian scans failing in docker [\#323](https://github.com/future-architect/vuls/issues/323)
- Local CVE DB is still checked, even if a CVE Dictionary URL is defined [\#316](https://github.com/future-architect/vuls/issues/316)
- vuls needs gmake. [\#313](https://github.com/future-architect/vuls/issues/313)
- patch request for FreeBSD [\#312](https://github.com/future-architect/vuls/issues/312)
- Report: failed to read from json \(Docker\) [\#294](https://github.com/future-architect/vuls/issues/294)
- -report-mail option does not output required mail header [\#282](https://github.com/future-architect/vuls/issues/282)
- PackInfo not found error when vuls scan. [\#281](https://github.com/future-architect/vuls/issues/281)
- Normalize character set [\#279](https://github.com/future-architect/vuls/issues/279)
- The number of Updatable Packages is different from the number of yum check-update [\#373](https://github.com/future-architect/vuls/issues/373)
- sudo is needed when exec yum check-update on RHEL7 [\#371](https://github.com/future-architect/vuls/issues/371)
- `123-3ubuntu4` should be marked as ChangelogLenientMatch [\#362](https://github.com/future-architect/vuls/issues/362)
- CentOS multi package invalid result [\#360](https://github.com/future-architect/vuls/issues/360)
- Parse error after check-update. \(Unknown format\) [\#359](https://github.com/future-architect/vuls/issues/359)
- Fix candidate to confidence. [\#354](https://github.com/future-architect/vuls/pull/354) ([kotakanbe](https://github.com/kotakanbe))
- Bug fix: not send e-mail to cc address [\#346](https://github.com/future-architect/vuls/pull/346) ([knqyf263](https://github.com/knqyf263))
- Change the command used for os detection from uname to freebsd-version [\#340](https://github.com/future-architect/vuls/pull/340) ([kotakanbe](https://github.com/kotakanbe))
- Fix error handling of detectOS [\#337](https://github.com/future-architect/vuls/pull/337) ([kotakanbe](https://github.com/kotakanbe))
- Fix infinite retry at size overrun error in Slack report [\#329](https://github.com/future-architect/vuls/pull/329) ([kotakanbe](https://github.com/kotakanbe))
- aptitude changelog defaults to using more, which is not interactive a… [\#324](https://github.com/future-architect/vuls/pull/324) ([jsulinski](https://github.com/jsulinski))
- Do not use sudo when echo [\#322](https://github.com/future-architect/vuls/pull/322) ([knqyf263](https://github.com/knqyf263))
- Reduce privilege requirements for commands that don't need sudo on Ubuntu/Debian [\#319](https://github.com/future-architect/vuls/pull/319) ([jsulinski](https://github.com/jsulinski))
- Don't check for a CVE DB when CVE Dictionary URL is defined [\#317](https://github.com/future-architect/vuls/pull/317) ([jsulinski](https://github.com/jsulinski))
- Fix typo contianer -\> container [\#314](https://github.com/future-architect/vuls/pull/314) ([justyns](https://github.com/justyns))
- Fix the changelog cache logic for ubuntu/debian [\#305](https://github.com/future-architect/vuls/pull/305) ([kotakanbe](https://github.com/kotakanbe))
- Fix yum updateinfo options [\#304](https://github.com/future-architect/vuls/pull/304) ([kotakanbe](https://github.com/kotakanbe))
- Update glide.lock to fix create-log-dir error. [\#303](https://github.com/future-architect/vuls/pull/303) ([kotakanbe](https://github.com/kotakanbe))
- Fix a bug in logging \(file output\) at scan command [\#302](https://github.com/future-architect/vuls/pull/302) ([kotakanbe](https://github.com/kotakanbe))
- Add -pipe flag \#294 [\#299](https://github.com/future-architect/vuls/pull/299) ([kotakanbe](https://github.com/kotakanbe))
- Fix RHEL5 scan stopped halfway [\#293](https://github.com/future-architect/vuls/pull/293) ([kotakanbe](https://github.com/kotakanbe))
- Fix amazon linux scan stopped halfway [\#292](https://github.com/future-architect/vuls/pull/292) ([kotakanbe](https://github.com/kotakanbe))
- Fix nil-ponter in TUI [\#388](https://github.com/future-architect/vuls/pull/388) ([kotakanbe](https://github.com/kotakanbe))
- Fix Bug of Mysql Backend [\#384](https://github.com/future-architect/vuls/pull/384) ([kotakanbe](https://github.com/kotakanbe))
- Fix scan confidence on Ubuntu/Debian/Raspbian \#362 [\#379](https://github.com/future-architect/vuls/pull/379) ([kotakanbe](https://github.com/kotakanbe))
- Fix updatalbe packages count \#373 [\#374](https://github.com/future-architect/vuls/pull/374) ([kotakanbe](https://github.com/kotakanbe))
- sudo yum check-update on RHEL [\#372](https://github.com/future-architect/vuls/pull/372) ([kotakanbe](https://github.com/kotakanbe))
- Change ssh option from -t to -tt [\#369](https://github.com/future-architect/vuls/pull/369) ([knqyf263](https://github.com/knqyf263))
- Increase the width of RequestPty [\#364](https://github.com/future-architect/vuls/pull/364) ([knqyf263](https://github.com/knqyf263))
**Closed issues:**
- vuls configtest --debugがsudoのチェックで止まってしまう [\#395](https://github.com/future-architect/vuls/issues/395)
- Add support for Oracle Linux [\#385](https://github.com/future-architect/vuls/issues/385)
- error on install - Ubuntu 16.04 [\#376](https://github.com/future-architect/vuls/issues/376)
- Unknown OS Type [\#335](https://github.com/future-architect/vuls/issues/335)
- mac os 10.12.3 make install error [\#334](https://github.com/future-architect/vuls/issues/334)
- assumeYes doesn't work because there is no else condition [\#320](https://github.com/future-architect/vuls/issues/320)
- Debian scan uses sudo where unnecessary [\#318](https://github.com/future-architect/vuls/issues/318)
- Add FreeBSD 11 to supported OS on documents. [\#311](https://github.com/future-architect/vuls/issues/311)
- docker fetchnvd failing [\#274](https://github.com/future-architect/vuls/issues/274)
- Latest version of labstack echo breaks installation [\#268](https://github.com/future-architect/vuls/issues/268)
- fetchnvd Fails using example loop [\#267](https://github.com/future-architect/vuls/issues/267)
**Merged pull requests:**
- fix typo in README.ja.md [\#394](https://github.com/future-architect/vuls/pull/394) ([lv7777](https://github.com/lv7777))
- Update Tutorial in README [\#387](https://github.com/future-architect/vuls/pull/387) ([kotakanbe](https://github.com/kotakanbe))
- Fix README [\#383](https://github.com/future-architect/vuls/pull/383) ([usiusi360](https://github.com/usiusi360))
- s/dictinary/dictionary typo [\#382](https://github.com/future-architect/vuls/pull/382) ([beuno](https://github.com/beuno))
- Fix Japanese typo [\#377](https://github.com/future-architect/vuls/pull/377) ([IMAI-Yuji](https://github.com/IMAI-Yuji))
- Improve kanji character [\#351](https://github.com/future-architect/vuls/pull/351) ([hasegawa-tomoki](https://github.com/hasegawa-tomoki))
- Add PULL\_REQUEST\_TEMPLATE.md [\#348](https://github.com/future-architect/vuls/pull/348) ([knqyf263](https://github.com/knqyf263))
- Update README [\#347](https://github.com/future-architect/vuls/pull/347) ([knqyf263](https://github.com/knqyf263))
- Fix test case [\#344](https://github.com/future-architect/vuls/pull/344) ([kotakanbe](https://github.com/kotakanbe))
- Fix typo [\#343](https://github.com/future-architect/vuls/pull/343) ([knqyf263](https://github.com/knqyf263))
- Rename Makefile to GNUmakefile \#313 [\#339](https://github.com/future-architect/vuls/pull/339) ([kotakanbe](https://github.com/kotakanbe))
- Update README [\#338](https://github.com/future-architect/vuls/pull/338) ([kotakanbe](https://github.com/kotakanbe))
- add error handling [\#332](https://github.com/future-architect/vuls/pull/332) ([kazuminn](https://github.com/kazuminn))
- Update readme [\#308](https://github.com/future-architect/vuls/pull/308) ([lapthorn](https://github.com/lapthorn))
- Update glide.lock to fix import error [\#306](https://github.com/future-architect/vuls/pull/306) ([knqyf263](https://github.com/knqyf263))
- Check whether echo is executable with nopasswd [\#298](https://github.com/future-architect/vuls/pull/298) ([knqyf263](https://github.com/knqyf263))
- Update docker README [\#297](https://github.com/future-architect/vuls/pull/297) ([knqyf263](https://github.com/knqyf263))
- update readme [\#296](https://github.com/future-architect/vuls/pull/296) ([galigalikun](https://github.com/galigalikun))
- remove unused import line. [\#358](https://github.com/future-architect/vuls/pull/358) ([ymomoi](https://github.com/ymomoi))
## [v0.2.0](https://github.com/future-architect/vuls/tree/v0.2.0) (2017-01-10)
[Full Changelog](https://github.com/future-architect/vuls/compare/v0.1.7...v0.2.0)
**Implemented enhancements:**
- Add report subcommand, change scan options. \#239 [\#270](https://github.com/future-architect/vuls/pull/270) ([kotakanbe](https://github.com/kotakanbe))
- Add --assume-yes to prepare \#260 [\#266](https://github.com/future-architect/vuls/pull/266) ([Code0x58](https://github.com/Code0x58))
- Use RFC3339 timestamps in the results [\#265](https://github.com/future-architect/vuls/pull/265) ([Code0x58](https://github.com/Code0x58))
**Fixed bugs:**
- vuls prepare failed to centos7 [\#275](https://github.com/future-architect/vuls/issues/275)
- Failed to scan on RHEL5 [\#94](https://github.com/future-architect/vuls/issues/94)
- Fix container os detection [\#287](https://github.com/future-architect/vuls/pull/287) ([jiazio](https://github.com/jiazio))
- Add date header to report mail. [\#283](https://github.com/future-architect/vuls/pull/283) ([ymomoi](https://github.com/ymomoi))
- Add Content-Type header to report/mail.go . [\#280](https://github.com/future-architect/vuls/pull/280) ([hogehogehugahuga](https://github.com/hogehogehugahuga))
- Keep output of "vuls scan -report-\*" to be same every times [\#272](https://github.com/future-architect/vuls/pull/272) ([yoheimuta](https://github.com/yoheimuta))
- Fix JSON-dir regex pattern \#265 [\#271](https://github.com/future-architect/vuls/pull/271) ([kotakanbe](https://github.com/kotakanbe))
- Stop quietly ignoring `--ssh-external` on Windows [\#263](https://github.com/future-architect/vuls/pull/263) ([Code0x58](https://github.com/Code0x58))
- Fix non-interactive `apt-get install` \#251 [\#253](https://github.com/future-architect/vuls/pull/253) ([Code0x58](https://github.com/Code0x58))
**Closed issues:**
- gocui.NewGui now takes a parameter [\#261](https://github.com/future-architect/vuls/issues/261)
- Add a `--yes` flag to bypass interactive prompt for `vuls prepare` [\#260](https://github.com/future-architect/vuls/issues/260)
- `vuls prepare` doesn't work on Debian host due to apt-get confirmation prompt [\#251](https://github.com/future-architect/vuls/issues/251)
**Merged pull requests:**
- Fix gocui.NewGui after signature change \#261 [\#262](https://github.com/future-architect/vuls/pull/262) ([Code0x58](https://github.com/Code0x58))
- Replace inconsistent tabs with spaces [\#254](https://github.com/future-architect/vuls/pull/254) ([Code0x58](https://github.com/Code0x58))
- Fix README [\#249](https://github.com/future-architect/vuls/pull/249) ([usiusi360](https://github.com/usiusi360))
## [v0.1.7](https://github.com/future-architect/vuls/tree/v0.1.7) (2016-11-08)
[Full Changelog](https://github.com/future-architect/vuls/compare/v0.1.6...v0.1.7)
**Implemented enhancements:**
- Enable to scan only docker container, without docker host [\#122](https://github.com/future-architect/vuls/issues/122)
- Add -skip-broken option \[CentOS only\] \#245 [\#248](https://github.com/future-architect/vuls/pull/248) ([kotakanbe](https://github.com/kotakanbe))
- Display unknown CVEs to TUI [\#244](https://github.com/future-architect/vuls/pull/244) ([kotakanbe](https://github.com/kotakanbe))
- Add the XML output [\#240](https://github.com/future-architect/vuls/pull/240) ([gleentea](https://github.com/gleentea))
- add '-ssh-external' option to prepare subcommand [\#234](https://github.com/future-architect/vuls/pull/234) ([mykstmhr](https://github.com/mykstmhr))
- Integrate OWASP Dependency Check [\#232](https://github.com/future-architect/vuls/pull/232) ([kotakanbe](https://github.com/kotakanbe))
- Add support for reading CVE data from MySQL. [\#225](https://github.com/future-architect/vuls/pull/225) ([oswell](https://github.com/oswell))
- Remove base docker image, -v shows commit hash [\#223](https://github.com/future-architect/vuls/pull/223) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- Support ignore CveIDs in config [\#222](https://github.com/future-architect/vuls/pull/222) ([kotakanbe](https://github.com/kotakanbe))
- Confirm before installing dependencies on prepare [\#219](https://github.com/future-architect/vuls/pull/219) ([kotakanbe](https://github.com/kotakanbe))
- Remove all.json [\#218](https://github.com/future-architect/vuls/pull/218) ([kotakanbe](https://github.com/kotakanbe))
- Add GitHub issue template [\#217](https://github.com/future-architect/vuls/pull/217) ([kotakanbe](https://github.com/kotakanbe))
- Improve makefile, -version shows git hash, fix README [\#216](https://github.com/future-architect/vuls/pull/216) ([kotakanbe](https://github.com/kotakanbe))
- change e-mail package from gomail to net/smtp [\#211](https://github.com/future-architect/vuls/pull/211) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- Add only-containers option to scan subcommand \#122 [\#190](https://github.com/future-architect/vuls/pull/190) ([kotakanbe](https://github.com/kotakanbe))
- Fix -results-dir option of scan subcommand [\#185](https://github.com/future-architect/vuls/pull/185) ([kotakanbe](https://github.com/kotakanbe))
- Show error when no scannable servers are detected. [\#177](https://github.com/future-architect/vuls/pull/177) ([kotakanbe](https://github.com/kotakanbe))
- Add sudo check to prepare subcommand [\#176](https://github.com/future-architect/vuls/pull/176) ([kotakanbe](https://github.com/kotakanbe))
- Supports yum --enablerepo option \(supports only base,updates for now\) [\#147](https://github.com/future-architect/vuls/pull/147) ([kotakanbe](https://github.com/kotakanbe))
**Fixed bugs:**
- Debian 8.6 \(jessie\) scan does not show vulnerable packages [\#235](https://github.com/future-architect/vuls/issues/235)
- panic: runtime error: index out of range - ubuntu 16.04 + vuls history [\#180](https://github.com/future-architect/vuls/issues/180)
- Moved golang.org/x/net/context to context [\#243](https://github.com/future-architect/vuls/pull/243) ([yoheimuta](https://github.com/yoheimuta))
- Fix changelog cache bug on Ubuntu and Debian \#235 [\#238](https://github.com/future-architect/vuls/pull/238) ([kotakanbe](https://github.com/kotakanbe))
- add '-ssh-external' option to prepare subcommand [\#234](https://github.com/future-architect/vuls/pull/234) ([mykstmhr](https://github.com/mykstmhr))
- Fixed error for the latest version of gocui [\#231](https://github.com/future-architect/vuls/pull/231) ([ymd38](https://github.com/ymd38))
- Handle the refactored gocui SetCurrentView method. [\#229](https://github.com/future-architect/vuls/pull/229) ([oswell](https://github.com/oswell))
- Fix locale env var LANG to LANGUAGE [\#215](https://github.com/future-architect/vuls/pull/215) ([kotakanbe](https://github.com/kotakanbe))
- Fixed bug with parsing update line on CentOS/RHEL [\#206](https://github.com/future-architect/vuls/pull/206) ([andyone](https://github.com/andyone))
- Fix defer cache.DB.close [\#201](https://github.com/future-architect/vuls/pull/201) ([kotakanbe](https://github.com/kotakanbe))
- Fix a help message of -report-azure-blob option [\#195](https://github.com/future-architect/vuls/pull/195) ([kotakanbe](https://github.com/kotakanbe))
- Fix error handling in tui [\#193](https://github.com/future-architect/vuls/pull/193) ([kotakanbe](https://github.com/kotakanbe))
- Fix not working changelog cache on Container [\#189](https://github.com/future-architect/vuls/pull/189) ([kotakanbe](https://github.com/kotakanbe))
- Fix release version detection on FreeBSD [\#184](https://github.com/future-architect/vuls/pull/184) ([kotakanbe](https://github.com/kotakanbe))
- Fix defer cahce.DB.close\(\) [\#183](https://github.com/future-architect/vuls/pull/183) ([kotakanbe](https://github.com/kotakanbe))
- Fix a mode of files/dir \(report, log\) [\#182](https://github.com/future-architect/vuls/pull/182) ([kotakanbe](https://github.com/kotakanbe))
- Fix a error when no json dirs are found under results \#180 [\#181](https://github.com/future-architect/vuls/pull/181) ([kotakanbe](https://github.com/kotakanbe))
- ssh-external option of configtest is not working \#178 [\#179](https://github.com/future-architect/vuls/pull/179) ([kotakanbe](https://github.com/kotakanbe))
**Closed issues:**
- --enable-repos of yum option [\#246](https://github.com/future-architect/vuls/issues/246)
- --skip-broken at yum option [\#245](https://github.com/future-architect/vuls/issues/245)
- Recent changes to gobui cause build failures [\#228](https://github.com/future-architect/vuls/issues/228)
- https://hub.docker.com/r/vuls/go-cve-dictionary/ is empty [\#208](https://github.com/future-architect/vuls/issues/208)
- Not able to install gomail fails [\#202](https://github.com/future-architect/vuls/issues/202)
- No results file created - vuls tui failed [\#199](https://github.com/future-architect/vuls/issues/199)
- Wrong file permissions for results/\*.json in official Docker container [\#197](https://github.com/future-architect/vuls/issues/197)
- Failed: Unknown OS Type [\#196](https://github.com/future-architect/vuls/issues/196)
- Segmentation fault with configtest [\#192](https://github.com/future-architect/vuls/issues/192)
- Failed to scan. err: No server defined. Check the configuration [\#187](https://github.com/future-architect/vuls/issues/187)
- vuls configtest -ssh-external doesnt work [\#178](https://github.com/future-architect/vuls/issues/178)
- apt-get update: time out [\#175](https://github.com/future-architect/vuls/issues/175)
- scanning on Centos6, but vuls recognizes debian. [\#174](https://github.com/future-architect/vuls/issues/174)
- Fix READMEja \#164 [\#173](https://github.com/future-architect/vuls/issues/173)
**Merged pull requests:**
- Update README \#225 [\#242](https://github.com/future-architect/vuls/pull/242) ([kotakanbe](https://github.com/kotakanbe))
- fix readme [\#241](https://github.com/future-architect/vuls/pull/241) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- Fix README \#234 [\#237](https://github.com/future-architect/vuls/pull/237) ([kotakanbe](https://github.com/kotakanbe))
- Update glide files [\#236](https://github.com/future-architect/vuls/pull/236) ([kotakanbe](https://github.com/kotakanbe))
- fix README [\#226](https://github.com/future-architect/vuls/pull/226) ([usiusi360](https://github.com/usiusi360))
- fix some misspelling. [\#221](https://github.com/future-architect/vuls/pull/221) ([ymomoi](https://github.com/ymomoi))
- fix docker readme [\#214](https://github.com/future-architect/vuls/pull/214) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- Fix ja document about typo [\#213](https://github.com/future-architect/vuls/pull/213) ([shokohara](https://github.com/shokohara))
- fix readme [\#212](https://github.com/future-architect/vuls/pull/212) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- fix README [\#207](https://github.com/future-architect/vuls/pull/207) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- fix typo [\#204](https://github.com/future-architect/vuls/pull/204) ([usiusi360](https://github.com/usiusi360))
- fix gitignore [\#191](https://github.com/future-architect/vuls/pull/191) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- Update glide.lock [\#188](https://github.com/future-architect/vuls/pull/188) ([kotakanbe](https://github.com/kotakanbe))
- Fix path in setup/docker/README [\#186](https://github.com/future-architect/vuls/pull/186) ([dladuke](https://github.com/dladuke))
- Vuls and vulsrepo are now separated [\#163](https://github.com/future-architect/vuls/pull/163) ([hikachan](https://github.com/hikachan))
## [v0.1.6](https://github.com/future-architect/vuls/tree/v0.1.6) (2016-09-12)
[Full Changelog](https://github.com/future-architect/vuls/compare/v0.1.5...v0.1.6)
**Implemented enhancements:**
- High speed scan on Ubuntu/Debian [\#172](https://github.com/future-architect/vuls/pull/172) ([kotakanbe](https://github.com/kotakanbe))
- Support CWE\(Common Weakness Enumeration\) [\#169](https://github.com/future-architect/vuls/pull/169) ([kotakanbe](https://github.com/kotakanbe))
- Enable to scan without sudo on amazon linux [\#167](https://github.com/future-architect/vuls/pull/167) ([kotakanbe](https://github.com/kotakanbe))
- Remove deprecated options -use-unattended-upgrades,-use-yum-plugin-security [\#161](https://github.com/future-architect/vuls/pull/161) ([kotakanbe](https://github.com/kotakanbe))
- delete sqlite3 [\#152](https://github.com/future-architect/vuls/pull/152) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
**Fixed bugs:**
- Failed to setup vuls docker [\#170](https://github.com/future-architect/vuls/issues/170)
- yum check-update error occurred when no reboot after kernel updating [\#165](https://github.com/future-architect/vuls/issues/165)
- error thrown from 'docker build .' [\#157](https://github.com/future-architect/vuls/issues/157)
- CVE-ID is truncated to 4 digits [\#153](https://github.com/future-architect/vuls/issues/153)
- 'yum update --changelog' stalled in 'vuls scan'. if ssh user is not 'root'. [\#150](https://github.com/future-architect/vuls/issues/150)
- Panic on packet scan [\#131](https://github.com/future-architect/vuls/issues/131)
- Update glide.lock \#170 [\#171](https://github.com/future-architect/vuls/pull/171) ([kotakanbe](https://github.com/kotakanbe))
- Fix detecting a platform on Azure [\#168](https://github.com/future-architect/vuls/pull/168) ([kotakanbe](https://github.com/kotakanbe))
- Fix parse error for yum check-update \#165 [\#166](https://github.com/future-architect/vuls/pull/166) ([kotakanbe](https://github.com/kotakanbe))
- Fix bug: Vuls on Docker [\#159](https://github.com/future-architect/vuls/pull/159) ([tjinjin](https://github.com/tjinjin))
- Fix CVE-ID is truncated to 4 digits [\#155](https://github.com/future-architect/vuls/pull/155) ([usiusi360](https://github.com/usiusi360))
- Fix yum update --changelog stalled when non-root ssh user on CentOS \#150 [\#151](https://github.com/future-architect/vuls/pull/151) ([kotakanbe](https://github.com/kotakanbe))
**Closed issues:**
- Support su for root privilege escalation [\#44](https://github.com/future-architect/vuls/issues/44)
- Support FreeBSD [\#34](https://github.com/future-architect/vuls/issues/34)
**Merged pull requests:**
- Change scripts for data fetching from jvn [\#164](https://github.com/future-architect/vuls/pull/164) ([kotakanbe](https://github.com/kotakanbe))
- Fix: setup vulsrepo [\#162](https://github.com/future-architect/vuls/pull/162) ([tjinjin](https://github.com/tjinjin))
- Fix-docker-vulsrepo-install [\#160](https://github.com/future-architect/vuls/pull/160) ([usiusi360](https://github.com/usiusi360))
- Reduce regular expression compilation [\#158](https://github.com/future-architect/vuls/pull/158) ([itchyny](https://github.com/itchyny))
- Add testcases for \#153 [\#156](https://github.com/future-architect/vuls/pull/156) ([kotakanbe](https://github.com/kotakanbe))
## [v0.1.5](https://github.com/future-architect/vuls/tree/v0.1.5) (2016-08-16)
[Full Changelog](https://github.com/future-architect/vuls/compare/v0.1.4...v0.1.5)
**Implemented enhancements:**
- Enable to scan without running go-cve-dictionary as server mode [\#84](https://github.com/future-architect/vuls/issues/84)
- Support high-speed scanning for CentOS [\#138](https://github.com/future-architect/vuls/pull/138) ([tai-ga](https://github.com/tai-ga))
- Add configtest subcommand. skip un-ssh-able servers. [\#134](https://github.com/future-architect/vuls/pull/134) ([kotakanbe](https://github.com/kotakanbe))
- Support -report-azure-blob option [\#130](https://github.com/future-architect/vuls/pull/130) ([kotakanbe](https://github.com/kotakanbe))
- Add optional key-values that will be outputted to JSON in config [\#117](https://github.com/future-architect/vuls/pull/117) ([kotakanbe](https://github.com/kotakanbe))
- Change dir structure [\#115](https://github.com/future-architect/vuls/pull/115) ([kotakanbe](https://github.com/kotakanbe))
- Add some validation of loading config. user, host and port [\#113](https://github.com/future-architect/vuls/pull/113) ([kotakanbe](https://github.com/kotakanbe))
- Support scanning with external ssh command [\#101](https://github.com/future-architect/vuls/pull/101) ([kotakanbe](https://github.com/kotakanbe))
- Detect Platform and get instance-id of amazon ec2 [\#95](https://github.com/future-architect/vuls/pull/95) ([kotakanbe](https://github.com/kotakanbe))
- Add -report-s3 option [\#92](https://github.com/future-architect/vuls/pull/92) ([kotakanbe](https://github.com/kotakanbe))
- Added FreeBSD support. [\#90](https://github.com/future-architect/vuls/pull/90) ([justyntemme](https://github.com/justyntemme))
- Add glide files for vendoring [\#89](https://github.com/future-architect/vuls/pull/89) ([kotakanbe](https://github.com/kotakanbe))
- Fix README, change -cvedbpath to -cve-dictionary-dbpath \#84 [\#85](https://github.com/future-architect/vuls/pull/85) ([kotakanbe](https://github.com/kotakanbe))
- Add option for it get cve detail from cve.sqlite3. [\#81](https://github.com/future-architect/vuls/pull/81) ([ymd38](https://github.com/ymd38))
- Add -report-text option, Fix small bug of report in japanese [\#78](https://github.com/future-architect/vuls/pull/78) ([kotakanbe](https://github.com/kotakanbe))
- Add JSONWriter, Fix CVE sort order of report [\#77](https://github.com/future-architect/vuls/pull/77) ([kotakanbe](https://github.com/kotakanbe))
**Fixed bugs:**
- Docker: Panic [\#76](https://github.com/future-architect/vuls/issues/76)
- Fix apt command to scan correctly when system locale is not english [\#149](https://github.com/future-architect/vuls/pull/149) ([kit494way](https://github.com/kit494way))
- Disable -ask-sudo-password for security reasons [\#148](https://github.com/future-architect/vuls/pull/148) ([kotakanbe](https://github.com/kotakanbe))
- Fix no tty error while executing with -external-ssh option [\#143](https://github.com/future-architect/vuls/pull/143) ([kotakanbe](https://github.com/kotakanbe))
- wrong log packages [\#141](https://github.com/future-architect/vuls/pull/141) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- Fix platform detection. [\#137](https://github.com/future-architect/vuls/pull/137) ([Rompei](https://github.com/Rompei))
- Fix nil pointer when scan with -cve-dictionary-dbpath and cpeNames [\#111](https://github.com/future-architect/vuls/pull/111) ([kotakanbe](https://github.com/kotakanbe))
- Remove vulndb file before pkg audit [\#110](https://github.com/future-architect/vuls/pull/110) ([kotakanbe](https://github.com/kotakanbe))
- Add error handling when unable to connect via ssh. status code: 255 [\#108](https://github.com/future-architect/vuls/pull/108) ([kotakanbe](https://github.com/kotakanbe))
- Enable to detect vulnerabilities on FreeBSD [\#98](https://github.com/future-architect/vuls/pull/98) ([kotakanbe](https://github.com/kotakanbe))
- Fix unknown format err while check-update on RHEL6.5 [\#93](https://github.com/future-architect/vuls/pull/93) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- Fix type of SMTP Port of discovery command's output [\#88](https://github.com/future-architect/vuls/pull/88) ([kotakanbe](https://github.com/kotakanbe))
- Fix error msg when go-cve-dictionary is unavailable \#84 [\#86](https://github.com/future-architect/vuls/pull/86) ([kotakanbe](https://github.com/kotakanbe))
- Fix error handling to avoid nil pointer err on debian [\#83](https://github.com/future-architect/vuls/pull/83) ([kotakanbe](https://github.com/kotakanbe))
- Fix nil pointer while doing apt-cache policy on ubuntu \#76 [\#82](https://github.com/future-architect/vuls/pull/82) ([kotakanbe](https://github.com/kotakanbe))
- fix log import url [\#79](https://github.com/future-architect/vuls/pull/79) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
- Fix error handling of gorequest [\#75](https://github.com/future-architect/vuls/pull/75) ([kotakanbe](https://github.com/kotakanbe))
- Fix freezing forever when no args specified in TUI mode [\#73](https://github.com/future-architect/vuls/pull/73) ([kotakanbe](https://github.com/kotakanbe))
- mv version.go version/version.go to run main.go without compile [\#71](https://github.com/future-architect/vuls/pull/71) ([sadayuki-matsuno](https://github.com/sadayuki-matsuno))
**Closed issues:**
- SSh password authentication failed on FreeBSD [\#99](https://github.com/future-architect/vuls/issues/99)
- BUG: -o pipefail is not work on FreeBSD's /bin/sh. because it isn't bash [\#91](https://github.com/future-architect/vuls/issues/91)
- Use ~/.ssh/config [\#62](https://github.com/future-architect/vuls/issues/62)
- SSH ciphers [\#37](https://github.com/future-architect/vuls/issues/37)
**Merged pull requests:**
- Update README \#138 [\#144](https://github.com/future-architect/vuls/pull/144) ([kotakanbe](https://github.com/kotakanbe))
- Fix a typo [\#142](https://github.com/future-architect/vuls/pull/142) ([dtan4](https://github.com/dtan4))
- Remove unnecessary step in readme of docker setup [\#140](https://github.com/future-architect/vuls/pull/140) ([mikkame](https://github.com/mikkame))
- Update logo [\#139](https://github.com/future-architect/vuls/pull/139) ([chanomaru](https://github.com/chanomaru))
- Update README.ja.md to fix wrong tips. [\#135](https://github.com/future-architect/vuls/pull/135) ([a2atsu](https://github.com/a2atsu))
- add tips about NVD JVN issue [\#133](https://github.com/future-architect/vuls/pull/133) ([a2atsu](https://github.com/a2atsu))
- Fix README wrong links [\#129](https://github.com/future-architect/vuls/pull/129) ([aomoriringo](https://github.com/aomoriringo))
- Add logo [\#126](https://github.com/future-architect/vuls/pull/126) ([chanomaru](https://github.com/chanomaru))
- Improve setup/docker [\#125](https://github.com/future-architect/vuls/pull/125) ([kotakanbe](https://github.com/kotakanbe))
- Fix scan command help [\#124](https://github.com/future-architect/vuls/pull/124) ([aomoriringo](https://github.com/aomoriringo))
- added dockernized-vuls with vulsrepo [\#121](https://github.com/future-architect/vuls/pull/121) ([hikachan](https://github.com/hikachan))
- Fix detect platform on azure and degital ocean [\#119](https://github.com/future-architect/vuls/pull/119) ([kotakanbe](https://github.com/kotakanbe))
- Remove json marshall-indent [\#118](https://github.com/future-architect/vuls/pull/118) ([kotakanbe](https://github.com/kotakanbe))
- Improve Readme.ja [\#116](https://github.com/future-architect/vuls/pull/116) ([kotakanbe](https://github.com/kotakanbe))
- Add architecture diag to README.md [\#114](https://github.com/future-architect/vuls/pull/114) ([kotakanbe](https://github.com/kotakanbe))
- Rename linux.go to base.go [\#100](https://github.com/future-architect/vuls/pull/100) ([kotakanbe](https://github.com/kotakanbe))
- Update README.md [\#74](https://github.com/future-architect/vuls/pull/74) ([yoshi-taka](https://github.com/yoshi-taka))
- Refactoring debian.go [\#72](https://github.com/future-architect/vuls/pull/72) ([kotakanbe](https://github.com/kotakanbe))
## [v0.1.4](https://github.com/future-architect/vuls/tree/v0.1.4) (2016-05-24)
[Full Changelog](https://github.com/future-architect/vuls/compare/v0.1.3...v0.1.4)
**Implemented enhancements:**
- Initial fetch from NVD is too heavy \(2.3 GB of memory consumed\) [\#27](https://github.com/future-architect/vuls/issues/27)
- Enable to show previous scan result [\#69](https://github.com/future-architect/vuls/pull/69) ([kotakanbe](https://github.com/kotakanbe))
- Add ignore-unscored-cves option [\#68](https://github.com/future-architect/vuls/pull/68) ([kotakanbe](https://github.com/kotakanbe))
- Support dynamic scanning docker container [\#67](https://github.com/future-architect/vuls/pull/67) ([kotakanbe](https://github.com/kotakanbe))
- Add version flag [\#65](https://github.com/future-architect/vuls/pull/65) ([kotakanbe](https://github.com/kotakanbe))
- Update Dockerfile [\#57](https://github.com/future-architect/vuls/pull/57) ([theonlydoo](https://github.com/theonlydoo))
- Update run.sh [\#56](https://github.com/future-architect/vuls/pull/56) ([theonlydoo](https://github.com/theonlydoo))
- Support Windows [\#33](https://github.com/future-architect/vuls/pull/33) ([mattn](https://github.com/mattn))
**Fixed bugs:**
- vuls scan -cvss-over does not work. [\#59](https://github.com/future-architect/vuls/issues/59)
- `panic: runtime error: invalid memory address or nil pointer dereference` when scan CentOS5.5 [\#58](https://github.com/future-architect/vuls/issues/58)
- It rans out of memory. [\#47](https://github.com/future-architect/vuls/issues/47)
- BUG: vuls scan on CentOS with Japanese environment. [\#43](https://github.com/future-architect/vuls/issues/43)
- yum --color=never [\#36](https://github.com/future-architect/vuls/issues/36)
- Failed to parse yum check-update [\#32](https://github.com/future-architect/vuls/issues/32)
- Pointless sudo [\#29](https://github.com/future-architect/vuls/issues/29)
- Can't init database in a path having blanks [\#26](https://github.com/future-architect/vuls/issues/26)
- Fix pointless sudo in debian.go \#29 [\#66](https://github.com/future-architect/vuls/pull/66) ([kotakanbe](https://github.com/kotakanbe))
- Fix error handling of httpGet in cve-client \#58 [\#64](https://github.com/future-architect/vuls/pull/64) ([kotakanbe](https://github.com/kotakanbe))
- Fix nil pointer at error handling of cve\_client \#58 [\#63](https://github.com/future-architect/vuls/pull/63) ([kotakanbe](https://github.com/kotakanbe))
- Set language en\_US. [\#61](https://github.com/future-architect/vuls/pull/61) ([pabroff](https://github.com/pabroff))
- Fix -cvss-over flag \#59 [\#60](https://github.com/future-architect/vuls/pull/60) ([kotakanbe](https://github.com/kotakanbe))
- Fix scan on Japanese environment. [\#55](https://github.com/future-architect/vuls/pull/55) ([pabroff](https://github.com/pabroff))
- Fix a typo: replace Depricated by Deprecated. [\#54](https://github.com/future-architect/vuls/pull/54) ([jody-frankowski](https://github.com/jody-frankowski))
- Fix yes no infinite loop while doing yum update --changelog on root@CentOS \#47 [\#50](https://github.com/future-architect/vuls/pull/50) ([pabroff](https://github.com/pabroff))
- Fix $servername in output of discover command [\#45](https://github.com/future-architect/vuls/pull/45) ([kotakanbe](https://github.com/kotakanbe))
## [v0.1.3](https://github.com/future-architect/vuls/tree/v0.1.3) (2016-04-21)
[Full Changelog](https://github.com/future-architect/vuls/compare/v0.1.2...v0.1.3)
**Implemented enhancements:**
- Add sudo support for prepare [\#11](https://github.com/future-architect/vuls/issues/11)
- Dockerfile? [\#10](https://github.com/future-architect/vuls/issues/10)
- Update README [\#41](https://github.com/future-architect/vuls/pull/41) ([theonlydoo](https://github.com/theonlydoo))
- Sparse dockerization [\#38](https://github.com/future-architect/vuls/pull/38) ([theonlydoo](https://github.com/theonlydoo))
- No password in config [\#35](https://github.com/future-architect/vuls/pull/35) ([kotakanbe](https://github.com/kotakanbe))
- Fr readme translation [\#23](https://github.com/future-architect/vuls/pull/23) ([novakin](https://github.com/novakin))
**Fixed bugs:**
- Issues updating CVE database behind https proxy [\#39](https://github.com/future-architect/vuls/issues/39)
- Vuls failed to parse yum check-update [\#24](https://github.com/future-architect/vuls/issues/24)
- Fix yum to yum --color=never \#36 [\#42](https://github.com/future-architect/vuls/pull/42) ([kotakanbe](https://github.com/kotakanbe))
- Fix parse yum check update [\#40](https://github.com/future-architect/vuls/pull/40) ([kotakanbe](https://github.com/kotakanbe))
- fix typo [\#31](https://github.com/future-architect/vuls/pull/31) ([blue119](https://github.com/blue119))
- Fix error while parsing yum check-update \#24 [\#30](https://github.com/future-architect/vuls/pull/30) ([kotakanbe](https://github.com/kotakanbe))
**Closed issues:**
- Unable to scan on ubuntu because changelog.ubuntu.com is down... [\#21](https://github.com/future-architect/vuls/issues/21)
- err: Not initialize\(d\) yet.. [\#16](https://github.com/future-architect/vuls/issues/16)
- Errors when using fish shell [\#8](https://github.com/future-architect/vuls/issues/8)
## [v0.1.2](https://github.com/future-architect/vuls/tree/v0.1.2) (2016-04-12)
[Full Changelog](https://github.com/future-architect/vuls/compare/v0.1.1...v0.1.2)
**Fixed bugs:**
- Maximum 6 nodes available to scan [\#12](https://github.com/future-architect/vuls/issues/12)
- panic: runtime error: index out of range [\#5](https://github.com/future-architect/vuls/issues/5)
- Fix sudo option on RedHat like Linux and change some messages. [\#20](https://github.com/future-architect/vuls/pull/20) ([kotakanbe](https://github.com/kotakanbe))
- Typo fix and updated readme [\#19](https://github.com/future-architect/vuls/pull/19) ([EuanKerr](https://github.com/EuanKerr))
- remove a period at the end of error messages. [\#18](https://github.com/future-architect/vuls/pull/18) ([kotakanbe](https://github.com/kotakanbe))
- fix error while yum updateinfo --security update on rhel@aws [\#17](https://github.com/future-architect/vuls/pull/17) ([kotakanbe](https://github.com/kotakanbe))
- Fixed typos [\#15](https://github.com/future-architect/vuls/pull/15) ([radarhere](https://github.com/radarhere))
- Typo fix in error messages [\#14](https://github.com/future-architect/vuls/pull/14) ([Bregor](https://github.com/Bregor))
- Fix index out of range error when the number of servers is over 6. \#12 [\#13](https://github.com/future-architect/vuls/pull/13) ([kotakanbe](https://github.com/kotakanbe))
- Revise small grammar mistakes in serverapi.go [\#9](https://github.com/future-architect/vuls/pull/9) ([cpobrien](https://github.com/cpobrien))
- Fix error handling in HTTP backoff function [\#7](https://github.com/future-architect/vuls/pull/7) ([kotakanbe](https://github.com/kotakanbe))
## [v0.1.1](https://github.com/future-architect/vuls/tree/v0.1.1) (2016-04-06)
[Full Changelog](https://github.com/future-architect/vuls/compare/v0.1.0...v0.1.1)
**Fixed bugs:**
- Typo in Exapmle [\#6](https://github.com/future-architect/vuls/pull/6) ([toli](https://github.com/toli))
## [v0.1.0](https://github.com/future-architect/vuls/tree/v0.1.0) (2016-04-04)
**Merged pull requests:**
- English translation [\#4](https://github.com/future-architect/vuls/pull/4) ([hikachan](https://github.com/hikachan))
- English translation [\#3](https://github.com/future-architect/vuls/pull/3) ([chewyinping](https://github.com/chewyinping))
- Add a Bitdeli Badge to README [\#2](https://github.com/future-architect/vuls/pull/2) ([bitdeli-chef](https://github.com/bitdeli-chef))
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*

View File

@@ -1,34 +0,0 @@
FROM golang:alpine as builder
RUN apk add --no-cache \
git \
make \
gcc \
musl-dev
ENV REPOSITORY github.com/future-architect/vuls
COPY . $GOPATH/src/$REPOSITORY
RUN cd $GOPATH/src/$REPOSITORY && make install
FROM alpine:3.11
MAINTAINER hikachan sadayuki-matsuno
ENV LOGDIR /var/log/vuls
ENV WORKDIR /vuls
RUN apk add --no-cache \
openssh-client \
ca-certificates \
git \
&& mkdir -p $WORKDIR $LOGDIR
COPY --from=builder /go/bin/vuls /usr/local/bin/
VOLUME ["$WORKDIR", "$LOGDIR"]
WORKDIR $WORKDIR
ENV PWD $WORKDIR
ENTRYPOINT ["vuls"]
CMD ["--help"]

View File

@@ -1,75 +1,42 @@
.PHONY: \
build \
install \
all \
vendor \
lint \
vet \
fmt \
fmtcheck \
pretest \
test \
cov \
clean
SRCS = $(shell git ls-files '*.go')
PKGS = $(shell go list ./...)
VERSION := $(shell git describe --tags --abbrev=0)
ifeq ($(VERSION), )
VERSION := $(shell git rev-parse --abbrev-ref HEAD)
endif
ifeq ($(shell git rev-parse --abbrev-ref HEAD), nightly)
VERSION := nightly
endif
REVISION := $(shell git rev-parse --short HEAD)
BUILDTIME := $(shell date "+%Y%m%d_%H%M%S")
LDFLAGS := -X 'github.com/future-architect/vuls/config.Version=$(VERSION)' \
-X 'github.com/future-architect/vuls/config.Revision=build-$(BUILDTIME)_$(REVISION)'
GO := GO111MODULE=on go
GO_OFF := GO111MODULE=off go
LDFLAGS := -ldflags "-s -w -X=github.com/future-architect/vuls/pkg/cmd/version.Version=$(VERSION) -X=github.com/future-architect/vuls/pkg/cmd/version.Revision=$(REVISION)"
GOPATH := $(shell go env GOPATH)
GOBIN := $(GOPATH)/bin
all: build
$(GOBIN)/golangci-lint:
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
build: main.go pretest fmt
$(GO) build -a -ldflags "$(LDFLAGS)" -o vuls $<
.PHONY: build
build:
go build $(LDFLAGS) ./cmd/vuls
b: main.go pretest fmt
$(GO) build -ldflags "$(LDFLAGS)" -o vuls $<
.PHONY: install
install:
go install $(LDFLAGS) ./cmd/vuls
install: main.go pretest
$(GO) install -ldflags "$(LDFLAGS)"
lint:
$(GO_OFF) get -u golang.org/x/lint/golint
golint $(PKGS)
vet:
echo $(PKGS) | xargs env $(GO) vet || exit;
fmt:
gofmt -s -w $(SRCS)
mlint:
$(foreach file,$(SRCS),gometalinter $(file) || exit;)
fmtcheck:
$(foreach file,$(SRCS),gofmt -s -d $(file);)
.PHONY: test
test: pretest
go test -race ./...
.PHONY: pretest
pretest: lint vet fmtcheck
test:
$(GO) test -cover -v ./... || exit;
.PHONY: lint
lint: $(GOBIN)/golangci-lint
golangci-lint run
unused:
$(foreach pkg,$(PKGS),unused $(pkg);)
.PHONY: vet
vet:
go vet ./...
cov:
@ go get -v github.com/axw/gocov/gocov
@ go get golang.org/x/tools/cmd/cover
gocov test | gocov report
clean:
echo $(PKGS) | xargs go clean || exit;
# trivy-to-vuls
build-trivy-to-vuls: pretest fmt
$(GO) build -o trivy-to-vuls contrib/trivy/cmd/*.go
# future-vuls
build-future-vuls: pretest fmt
$(GO) build -o future-vuls contrib/future-vuls/cmd/*.go
.PHONY: fmtcheck
fmtcheck:
gofmt -s -d .

661
LICENSE
View File

@@ -1,661 +0,0 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.

2
NOTICE
View File

@@ -1,2 +0,0 @@
Vuls Copyright (C) 2016 Future Corporation , Japan.

641
README.md
View File

@@ -1,190 +1,513 @@
# Vuls: VULnerability Scanner
[![Slack](https://img.shields.io/badge/slack-join-blue.svg)](http://goo.gl/forms/xm5KFo35tu)
[![License](https://img.shields.io/github/license/future-architect/vuls.svg?style=flat-square)](https://github.com/future-architect/vuls/blob/master/LICENSE)
[![Build Status](https://travis-ci.org/future-architect/vuls.svg?branch=master)](https://travis-ci.org/future-architect/vuls)
[![Go Report Card](https://goreportcard.com/badge/github.com/future-architect/vuls)](https://goreportcard.com/report/github.com/future-architect/vuls)
[![Contributors](https://img.shields.io/github/contributors/future-architect/vuls.svg)](https://github.com/future-architect/vuls/graphs/contributors)
## NOTE
This is the nightly branch and provides the latest functionality.
Please use the master branch if you want to use it stably, as destructive changes are also made.
![Vuls-logo](img/vuls_logo.png)
## Usage
Vulnerability scanner for Linux/FreeBSD, agent-less, written in Go.
We have a slack team. [Join slack team](http://goo.gl/forms/xm5KFo35tu)
Twitter: [@vuls_en](https://twitter.com/vuls_en)
### 1. Nightly Vuls installation
![Vuls-Abstract](img/vuls-abstract.png)
```console
$ go install github.com/future-architect/vuls/cmd/vuls@nightly
$ vuls version
vuls nightly 2ef5390
```
![Vulsrepo](https://raw.githubusercontent.com/usiusi360/vulsrepo/master/gallery/demo.gif)
### 2. DB Fetch
[![asciicast](https://asciinema.org/a/3y9zrf950agiko7klg8abvyck.png)](https://asciinema.org/a/3y9zrf950agiko7klg8abvyck)
```console
$ vuls db fetch
```
![Vuls-slack](img/vuls-slack-en.png)
### 3. init config & configuration change
----
Execute the following command to output a config template to stdout.
Make a file of it and change the necessary host part, path to the DB, etc. to suit your environment.
## Abstract
```console
$ vuls config init
```
For a system administrator, having to perform security vulnerability analysis and software update on a daily basis can be a burden.
To avoid downtime in a production environment, it is common for a system administrator to choose not to use the automatic update option provided by the package manager and to perform update manually.
This leads to the following problems.
### Optional. add to list of known hosts
- The system administrator will have to constantly watch out for any new vulnerabilities in NVD (National Vulnerability Database) or similar databases.
- It might be impossible for the system administrator to monitor all the software if there are a large number of software packages installed in the server.
- It is expensive to perform analysis to determine the servers affected by new vulnerabilities. The possibility of overlooking a server or two during analysis is there.
When using remote as the host type, make an ssh connection to the remote host.
Before scanning, register the host in the known_hosts.
Vuls is a tool created to solve the problems listed above. It has the following characteristics.
```console
$ ssh -i /home/mainek00n/.ssh/id_rsa -p 2222 root@127.0.0.1
The authenticity of host '[127.0.0.1]:2222 ([127.0.0.1]:2222)' can't be established.
ED25519 key fingerprint is SHA256:dK+aO73n6hymIC3+3yFFHpvyNu/txTYi/LXvMl/TzOk.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[127.0.0.1]:2222' (ED25519) to the list of known hosts.
```
- Informs users of the vulnerabilities that are related to the system.
- Informs users of the servers that are affected.
- Vulnerability detection is done automatically to prevent any oversight.
- A report is generated on a regular basis using CRON or other methods. to manage vulnerability.
### 4. Scan
![Vuls-Motivation](img/vuls-motivation.png)
```console
$ vuls scan
Scan Summary
============
local (ubuntu 22.04): success ospkg: 2663, cpe: 0 installed
remote (debian 11): success ospkg: 319, cpe: 0 installed
cpe: success ospkg: 0, cpe: 1 installed
----
or
## Main Features
$ vuls server
### Scan for any vulnerabilities in Linux/FreeBSD Server
$ cat machine.json
{
"contents": [
{
"content_type": "os-release",
"content": "PRETTY_NAME=\"Ubuntu 22.04.1 LTS\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"22.04\"\nVERSION=\"22.04.1 LTS (Jammy Jellyfish)\"\nVERSION_CODENAME=jammy\nID=ubuntu\nID_LIKE=debian\nHOME_URL=\"https:\/\/www.ubuntu.com\/\"\nSUPPORT_URL=\"https:\/\/help.ubuntu.com\/\"\nBUG_REPORT_URL=\"https:\/\/bugs.launchpad.net\/ubuntu\/\"\nPRIVACY_POLICY_URL=\"https:\/\/www.ubuntu.com\/legal\/terms-and-policies\/privacy-policy\"\nUBUNTU_CODENAME=jammy"
},
{
"content_type": "dpkg",
"content": "accountsservice,ii ,22.07.5-2ubuntu1.3,amd64,accountsservice,22.07.5-2ubuntu1.3\nacl,ii ,2.3.1-1,amd64,acl,2.3.1-1\nnvim-common,ii ,2:8.2.3995-1ubuntu2.1,all,vim,2:8.2.3995-1ubuntu2.1\n"
}
]
}
[Supports major Linux/FreeBSD](https://vuls.io/docs/en/supported-os.html)
$ curl -s -X POST -H "Content-Type: application/json" -d @machine.json 127.0.0.1:5515/scan | jq
{
"name": "8002e134-dc2d-4786-96b3-e751103fe5c3",
"family": "ubuntu",
"release": "22.04",
"scanned_at": "2022-11-14T10:41:07.558379311+09:00",
"packages": {
"kernel": {},
"os_pkg": {
"accountsservice": {
"name": "accountsservice",
"version": "22.07.5-2ubuntu1.3",
"arch": "amd64",
"src_name": "accountsservice",
"src_version": "22.07.5-2ubuntu1.3"
},
"acl": {
"name": "acl",
"version": "2.3.1-1",
"arch": "amd64",
"src_name": "acl",
"src_version": "2.3.1-1"
},
"nvim-common": {
"name": "nvim-common",
"version": "2:8.2.3995-1ubuntu2.1",
"arch": "all",
"src_name": "vim",
"src_version": "2:8.2.3995-1ubuntu2.1"
}
}
},
"config": {}
}
```
- Alpine, Amazon Linux, CentOS, Debian, Oracle Linux, Raspbian, RHEL, SUSE Enterprise Linux, and Ubuntu
- FreeBSD
- Cloud, on-premise, Running Docker Container
### 5. Detect
### High-quality scan
```console
$ vuls detect
Detect Summary
==============
local (ubuntu 22.04) : success 143 CVEs detected
remote (debian 11) : success 101 CVEs detected
cpe : success 7 CVEs detected
- Vulnerability Database
- [NVD](https://nvd.nist.gov/)
- [JVN(Japanese)](http://jvndb.jvn.jp/apis/myjvn/)
or
- OVAL
- [Red Hat](https://www.redhat.com/security/data/oval/)
- [Debian](https://www.debian.org/security/oval/)
- [Ubuntu](https://people.canonical.com/~ubuntu-security/oval/)
- [SUSE](http://ftp.suse.com/pub/projects/security/oval/)
- [Oracle Linux](https://linux.oracle.com/security/oval/)
$ vuls server
- Security Advisory
- [Alpine-secdb](https://git.alpinelinux.org/cgit/alpine-secdb/)
- [Red Hat Security Advisories](https://access.redhat.com/security/security-updates/)
- [Debian Security Bug Tracker](https://security-tracker.debian.org/tracker/)
$ cat scan.json
{
"name": "8002e134-dc2d-4786-96b3-e751103fe5c3",
"family": "ubuntu",
"release": "22.04",
"scanned_at": "2022-11-14T10:41:07.558379311+09:00",
"packages": {
"kernel": {},
"os_pkg": {
"accountsservice": {
"name": "accountsservice",
"version": "22.07.5-2ubuntu1.3",
"arch": "amd64",
"src_name": "accountsservice",
"src_version": "22.07.5-2ubuntu1.3"
},
"acl": {
"name": "acl",
"version": "2.3.1-1",
"arch": "amd64",
"src_name": "acl",
"src_version": "2.3.1-1"
},
"nvim-common": {
"name": "nvim-common",
"version": "2:8.2.3995-1ubuntu2.1",
"arch": "all",
"src_name": "vim",
"src_version": "2:8.2.3995-1ubuntu2.1"
}
}
},
"config": {}
}
- Commands(yum, zypper, pkg-audit)
- RHSA / ALAS / ELSA / FreeBSD-SA
- Changelog
$ curl -s -X POST -H "Content-Type: application/json" -d @scan.json 127.0.0.1:5515/detect | jq
{
"name": "0c33d5fc-add4-465b-9ffa-90e74036259d",
"family": "ubuntu",
"release": "22.04",
"scanned_at": "2022-11-14T10:42:31.863598309+09:00",
"detectedd_at": "2022-11-14T10:42:50.677085953+09:00",
"packages": {
"kernel": {},
"os_pkg": {
"accountsservice": {
"name": "accountsservice",
"version": "22.07.5-2ubuntu1.3",
"arch": "amd64",
"src_name": "accountsservice",
"src_version": "22.07.5-2ubuntu1.3"
},
"acl": {
"name": "acl",
"version": "2.3.1-1",
"arch": "amd64",
"src_name": "acl",
"src_version": "2.3.1-1"
},
"nvim-common": {
"name": "nvim-common",
"version": "2:8.2.3995-1ubuntu2.1",
"arch": "all",
"src_name": "vim",
"src_version": "2:8.2.3995-1ubuntu2.1"
}
}
},
"scanned_cves": {
"CVE-2022-0128": {
"content": {
"official": {
"id": "CVE-2022-0128",
"advisory": [
"mitre",
"nvd",
"alpine:3.12:CVE-2022-0128",
"alpine:3.13:CVE-2022-0128",
"alpine:3.14:CVE-2022-0128",
"alpine:3.15:CVE-2022-0128",
"alpine:3.16:CVE-2022-0128",
"amazon:2022:ALAS2022-2022-014",
"debian_security_tracker:11:CVE-2022-0128",
"debian_security_tracker:12:CVE-2022-0128",
"debian_security_tracker:sid:CVE-2022-0128",
"debian_security_tracker:10:CVE-2022-0128",
"redhat_oval:6-including-unpatched:oval:com.redhat.unaffected:def:20220128",
"redhat_oval:7-including-unpatched:oval:com.redhat.unaffected:def:20220128",
"redhat_oval:8-including-unpatched:oval:com.redhat.unaffected:def:20220128",
"redhat_oval:9-including-unpatched:oval:com.redhat.unaffected:def:20220128",
"suse_oval:opensuse.leap.15.3:oval:org.opensuse.security:def:20220128",
"suse_oval:opensuse.leap.15.4:oval:org.opensuse.security:def:20220128",
"suse_oval:suse.linux.enterprise.desktop.15:oval:org.opensuse.security:def:20220128",
"suse_oval:suse.linux.enterprise.server.12:oval:org.opensuse.security:def:20220128",
"suse_oval:suse.linux.enterprise.server.15:oval:org.opensuse.security:def:20220128",
"suse_cvrf",
"ubuntu_oval:14.04:oval:com.ubuntu.trusty:def:202201280000000",
"ubuntu_oval:16.04:oval:com.ubuntu.xenial:def:202201280000000",
"ubuntu_oval:21.04:oval:com.ubuntu.hirsute:def:202201280000000",
"ubuntu_oval:22.04:oval:com.ubuntu.jammy:def:202201280000000",
"ubuntu_oval:22.10:oval:com.ubuntu.kinetic:def:202201280000000",
"ubuntu_security_tracker"
],
"title": "CVE-2022-0128",
"description": "vim is vulnerable to Out-of-bounds Read",
"cvss": [
{
"source": "nvd",
"version": "2.0",
"vector": "AV:N/AC:M/Au:N/C:P/I:P/A:P",
"score": 6.8,
"severity": "MEDIUM"
},
{
"source": "nvd",
"version": "3.1",
"vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
"score": 7.8,
"severity": "HIGH"
},
{
"source": "amazon:2022:ALAS2022-2022-014",
"severity": "Important"
},
{
"source": "redhat_oval:7-including-unpatched:oval:com.redhat.unaffected:def:20220128",
"version": "3.1",
"vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H",
"score": 6.1,
"severity": "moderate"
},
{
"source": "redhat_oval:8-including-unpatched:oval:com.redhat.unaffected:def:20220128",
"version": "3.1",
"vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H",
"score": 6.1,
"severity": "moderate"
},
{
"source": "redhat_oval:9-including-unpatched:oval:com.redhat.unaffected:def:20220128",
"version": "3.1",
"vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H",
"score": 6.1,
"severity": "moderate"
},
{
"source": "redhat_oval:6-including-unpatched:oval:com.redhat.unaffected:def:20220128",
"version": "3.1",
"vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H",
"score": 6.1,
"severity": "moderate"
},
{
"source": "suse_oval:opensuse.leap.15.4:oval:org.opensuse.security:def:20220128",
"version": "3.1",
"vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N",
"score": 3.3,
"severity": "low"
},
{
"source": "suse_oval:suse.linux.enterprise.desktop.15:oval:org.opensuse.security:def:20220128",
"version": "3.1",
"vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N",
"score": 3.3,
"severity": "low"
},
{
"source": "suse_oval:suse.linux.enterprise.server.12:oval:org.opensuse.security:def:20220128",
"version": "3.1",
"vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N",
"score": 3.3,
"severity": "low"
},
{
"source": "suse_oval:suse.linux.enterprise.server.15:oval:org.opensuse.security:def:20220128",
"version": "3.1",
"vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N",
"score": 3.3,
"severity": "low"
},
{
"source": "suse_oval:opensuse.leap.15.3:oval:org.opensuse.security:def:20220128",
"version": "3.1",
"vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N",
"score": 3.3,
"severity": "low"
},
{
"source": "suse_cvrf",
"version": "2.0",
"vector": "AV:N/AC:M/Au:N/C:P/I:P/A:P",
"score": 6.8
},
{
"source": "suse_cvrf",
"version": "3.1",
"vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N",
"score": 3.3
},
{
"source": "ubuntu_oval:14.04:oval:com.ubuntu.trusty:def:202201280000000",
"severity": "Medium"
},
{
"source": "ubuntu_oval:16.04:oval:com.ubuntu.xenial:def:202201280000000",
"severity": "Medium"
},
{
"source": "ubuntu_oval:21.04:oval:com.ubuntu.hirsute:def:202201280000000",
"severity": "Medium"
},
{
"source": "ubuntu_oval:22.04:oval:com.ubuntu.jammy:def:202201280000000",
"severity": "Medium"
},
{
"source": "ubuntu_oval:22.10:oval:com.ubuntu.kinetic:def:202201280000000",
"severity": "Medium"
},
{
"source": "ubuntu_security_tracker",
"severity": "medium"
},
{
"source": "ubuntu_security_tracker",
"version": "3.1",
"vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
"score": 7.8,
"severity": "HIGH"
}
],
"epss": {
"epss": 0.01537,
"percentile": 0.73989
},
"cwe": [
{
"source": [
"nvd",
"redhat_oval:6-including-unpatched:oval:com.redhat.unaffected:def:20220128",
"redhat_oval:7-including-unpatched:oval:com.redhat.unaffected:def:20220128",
"redhat_oval:8-including-unpatched:oval:com.redhat.unaffected:def:20220128",
"redhat_oval:9-including-unpatched:oval:com.redhat.unaffected:def:20220128"
],
"id": "125"
}
],
"exploit": [
{
"source": [
"nvd",
"inthewild",
"trickest"
],
"url": "https://huntr.dev/bounties/63f51299-008a-4112-b85b-1e904aadd4ba"
}
],
"published": "2022-01-06T17:15:00Z",
"modified": "2022-11-02T13:18:00Z",
"reference": [
"http://www.openwall.com/lists/oss-security/2022/01/15/1",
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-4166",
"https://access.redhat.com/security/cve/CVE-2022-0128",
"https://lists.suse.com/pipermail/sle-security-updates/2022-July/011493.html",
"https://lists.suse.com/pipermail/sle-security-updates/2022-July/011575.html",
"https://lists.suse.com/pipermail/sle-security-updates/2022-July/011592.html",
"https://lists.suse.com/pipermail/sle-security-updates/2022-June/011301.html",
"https://bugs.launchpad.net/ubuntu/+bug/https://huntr.dev/bounties/63f51299-008a-4112-b85b-1e904aadd4ba",
"https://support.apple.com/kb/HT213343",
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-4019",
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-4187",
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-4193",
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0156",
"https://lists.suse.com/pipermail/sle-security-updates/2022-August/011821.html",
"https://lists.suse.com/pipermail/sle-security-updates/2022-September/012143.html",
"https://bugzilla.suse.com/1194388",
"https://www.suse.com/support/security/rating/",
"http://people.canonical.com/~ubuntu-security/cve/2022/CVE-2022-0128.html",
"http://seclists.org/fulldisclosure/2022/May/35",
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-4069",
"https://www.suse.com/security/cve/CVE-2022-0128",
"https://lists.suse.com/pipermail/sle-security-updates/2022-July/011573.html",
"http://seclists.org/fulldisclosure/2022/Mar/29",
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0128",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0128",
"https://lists.suse.com/pipermail/sle-security-updates/2022-August/011795.html",
"https://lists.suse.com/pipermail/sle-security-updates/2022-July/011495.html",
"https://ubuntu.com/security/CVE-2022-0128",
"https://huntr.dev/bounties/63f51299-008a-4112-b85b-1e904aadd4ba",
"http://seclists.org/fulldisclosure/2022/Jul/14",
"https://security.gentoo.org/glsa/202208-32",
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0158",
"https://lists.suse.com/pipermail/sle-security-updates/2022-July/011591.html",
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-4136",
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-4173",
"https://lists.suse.com/pipermail/sle-security-updates/2022-July/011494.html",
"https://support.apple.com/kb/HT213183",
"https://support.apple.com/kb/HT213256",
"https://github.com/vim/vim/commit/d3a117814d6acbf0dca3eff1a7626843b9b3734a",
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-4192",
"https://lists.suse.com/pipermail/sle-security-updates/2022-July/011574.html",
"https://lists.suse.com/pipermail/sle-security-updates/2022-July/011593.html"
]
}
},
"affected_packages": [
{
"name": "vim",
"source": "official:ubuntu_security_tracker:CVE-2022-0128",
"status": "needed"
}
]
},
...
},
"config": {
"detect": {
"path": "/home/mainek00n/github/github.com/future-architect/vuls/vuls.db",
"result_dir": ""
}
}
}
```
- PoC, Exploit
- [Exploit Database](https://www.exploit-db.com/)
- [Metasploit-Framework modules](https://www.rapid7.com/db/?q=&type=metasploit)
### 6. Report
- CERT
- [US-CERT](https://www.us-cert.gov/ncas/alerts)
- [JPCERT](http://www.jpcert.or.jp/at/2019.html)
```console
$ vuls report --format list
cpe
===
+----------------+----------------------------+------+----------+-------+----------------------------------------+--------+----------+
| CVEID | VECTOR | CVSS | EPSS | KEV | PACKAGE | STATUS | SOURCE |
+----------------+----------------------------+------+----------+-------+----------------------------------------+--------+----------+
| CVE-2021-44228 | AV:N/AC:M/Au:N/C:C/I:C/A:C | 9.3 | 0.911590 | true | cpe:2.3:a:apache:log4j:*:*:*:*:*:*:*:* | | official |
+----------------+----------------------------+------+----------+-------+ +--------+ +
| CVE-2022-23307 | AV:N/AC:L/Au:S/C:C/I:C/A:C | 9.0 | 0.011640 | false | | | |
+----------------+----------------------------+------+----------+ + +--------+ +
| CVE-2021-44832 | AV:N/AC:M/Au:S/C:C/I:C/A:C | 8.5 | 0.686370 | | | | |
+----------------+----------------------------+------+----------+ + +--------+ +
| CVE-2022-23305 | AV:N/AC:M/Au:N/C:P/I:P/A:P | 6.8 | 0.017420 | | | | |
+----------------+----------------------------+------+----------+ + +--------+ +
| CVE-2022-23302 | AV:N/AC:M/Au:S/C:P/I:P/A:P | 6.0 | 0.091480 | | | | |
+----------------+----------------------------+------+----------+ + +--------+ +
| CVE-2021-45046 | AV:N/AC:H/Au:N/C:P/I:P/A:P | 5.1 | 0.719510 | | | | |
+----------------+----------------------------+------+----------+ + +--------+ +
| CVE-2021-45105 | AV:N/AC:M/Au:N/C:N/I:N/A:P | 4.3 | 0.442620 | | | | |
+----------------+----------------------------+------+----------+-------+----------------------------------------+--------+----------+
- Libraries
- [Node.js Security Working Group](https://github.com/nodejs/security-wg)
- [Ruby Advisory Database](https://github.com/rubysec/ruby-advisory-db)
- [Safety DB(Python)](https://github.com/pyupio/safety-db)
- [PHP Security Advisories Database](https://github.com/FriendsOfPHP/security-advisories)
- [RustSec Advisory Database](https://github.com/RustSec/advisory-db)
local (ubuntu 22.04)
====================
+----------------+----------------------------+------+----------+-------+-----------------------+----------+----------+
| CVEID | VECTOR | CVSS | EPSS | KEV | PACKAGE | STATUS | SOURCE |
+----------------+----------------------------+------+----------+-------+-----------------------+----------+----------+
| CVE-2022-0318 | AV:N/AC:L/Au:N/C:P/I:P/A:P | 7.5 | 0.011830 | false | vim | needed | official |
+----------------+----------------------------+------+----------+ +-----------------------+ + +
| CVE-2022-25255 | AV:L/AC:L/Au:N/C:C/I:C/A:C | 7.2 | 0.009500 | | qtbase-opensource-src | | |
+----------------+ + +----------+ +-----------------------+ + +
| CVE-2022-0995 | | | 0.024480 | | linux | | |
+----------------+----------------------------+------+----------+ +-----------------------+ + +
...
+----------------+----------------------------+------+----------+ +-----------------------+----------+ +
| CVE-2022-42799 | | | 0.011080 | | webkit2gtk | needed | |
+----------------+----------------------------+------+----------+ +-----------------------+ + +
| CVE-2022-3061 | | | 0.008900 | | linux | | |
+----------------+----------------------------+------+----------+-------+-----------------------+----------+----------+
- WordPress
- [WPVulnDB](https://wpvulndb.com/api)
remote (debian 11)
==================
+----------------+----------------------------+------+----------+-------+------------+--------+----------+
| CVEID | VECTOR | CVSS | EPSS | KEV | PACKAGE | STATUS | SOURCE |
+----------------+----------------------------+------+----------+-------+------------+--------+----------+
| CVE-2022-31782 | AV:N/AC:M/Au:N/C:P/I:P/A:P | 6.8 | 0.008850 | false | freetype | open | official |
+----------------+ + +----------+ +------------+ + +
| CVE-2022-1304 | | | 0.010360 | | e2fsprogs | | |
+----------------+----------------------------+------+----------+ +------------+ + +
| CVE-2022-1587 | AV:N/AC:L/Au:N/C:P/I:N/A:P | 6.4 | 0.011080 | | pcre2 | | |
+----------------+ + +----------+ + + + +
| CVE-2022-1586 | | | 0.011830 | | | | |
+----------------+----------------------------+------+ + +------------+ + +
| CVE-2022-2097 | AV:N/AC:L/Au:N/C:P/I:N/A:N | 5.0 | | | openssl | | |
+----------------+----------------------------+------+----------+ +------------+ + +
...
+----------------+----------------------------+------+----------+ +------------+ + +
| CVE-2022-38126 | | | 0.008850 | | binutils | | |
+----------------+----------------------------+------+ + +------------+ + +
| CVE-2022-41848 | | | | | linux | | |
+----------------+----------------------------+------+----------+-------+------------+--------+----------+
### Scan mode
[Fast Scan](https://vuls.io/docs/en/architecture-fast-scan.html)
- Scan without root privilege, no dependencies
- Almost no load on the scan target server
- Offline mode scan with no internet access. (CentOS, Debian, Oracle Linux, Red Hat, and Ubuntu)
[Fast Root Scan](https://vuls.io/docs/en/architecture-fast-root-scan.html)
- Scan with root privilege
- Almost no load on the scan target server
- Detect processes affected by update using yum-ps (Amazon Linux, CentOS, Oracle Linux, and RedHat)
- Detect processes which updated before but not restarting yet using checkrestart of debian-goodies (Debian and Ubuntu)
- Offline mode scan with no internet access. (CentOS, Debian, Oracle Linux, Red Hat, and Ubuntu)
### [Remote, Local scan mode, Server mode](https://vuls.io/docs/en/architecture-remote-local.html)
[Remote scan mode](https://vuls.io/docs/en/architecture-remote-scan.html)
- User is required to only set up one machine that is connected to other target servers via SSH
[Local scan mode](https://vuls.io/docs/en/architecture-local-scan.html)
- If you don't want the central Vuls server to connect to each server by SSH, you can use Vuls in the Local Scan mode.
[Server mode](https://vuls.io/docs/en/usage-server.html)
- First, start Vuls in server mode and listen as an HTTP server.
- Next, issue a command on the scan target server to collect software information. Then send the result to Vuls Server via HTTP. You receive the scan results as JSON format.
- No SSH needed, No Scanner needed. Only issuing Linux commands directory on the scan target server.
### **Dynamic** Analysis
- It is possible to acquire the state of the server by connecting via SSH and executing the command.
- Vuls warns when the scan target server was updated the kernel etc. but not restarting it.
### Scan vulnerabilities of non-OS-packages
- Libraries of programming language
- Self-compiled software
- Network Devices
Vuls has some options to detect the vulnerabilities
- [Lockfile based Scan](https://vuls.io/docs/en/usage-scan-non-os-packages.html#library-vulns-scan)
- [GitHub Integration](https://vuls.io/docs/en/usage-scan-non-os-packages.html#usage-integrate-with-github-security-alerts)
- [Common Platform Enumeration (CPE) based Scan](https://vuls.io/docs/en/usage-scan-non-os-packages.html#cpe-scan)
- [OWASP Dependency Check Integration](https://vuls.io/docs/en/usage-scan-non-os-packages.html#usage-integrate-with-owasp-dependency-check-to-automatic-update-when-the-libraries-are-updated-experimental)
## Scan WordPress core, themes, plugins
- [Scan WordPress](https://vuls.io/docs/en/usage-scan-wordpress.html)
## MISC
- Nondestructive testing
- Pre-authorization is *NOT* necessary before scanning on AWS
- Vuls works well with Continuous Integration since tests can be run every day. This allows you to find vulnerabilities very quickly.
- Auto-generation of configuration file template
- Auto-detection of servers set using CIDR, generate configuration file template
- Email and Slack notification is possible (supports Japanese language)
- Scan result is viewable on accessory software, TUI Viewer in a terminal or Web UI ([VulsRepo](https://github.com/ishiDACo/vulsrepo)).
----
## What Vuls Doesn't Do
- Vuls doesn't update the vulnerable packages.
----
## Document
For more information such as Installation, Tutorial, Usage, visit [vuls.io](https://vuls.io/)
[日本語翻訳ドキュメント](https://vuls.io/ja/)
----
## Authors
kotakanbe ([@kotakanbe](https://twitter.com/kotakanbe)) created vuls and [these fine people](https://github.com/future-architect/vuls/graphs/contributors) have contributed.
----
## Stargazers over time
[![Stargazers over time](https://starcharts.herokuapp.com/future-architect/vuls.svg)](https://starcharts.herokuapp.com/future-architect/vuls)
-----;
## License
Please see [LICENSE](https://github.com/future-architect/vuls/blob/master/LICENSE).
```

171
cache/bolt.go vendored
View File

@@ -1,171 +0,0 @@
package cache
import (
"encoding/json"
"time"
"github.com/boltdb/bolt"
"github.com/future-architect/vuls/util"
"github.com/sirupsen/logrus"
"golang.org/x/xerrors"
)
// Bolt holds a pointer of bolt.DB
// boltdb is used to store a cache of Changelogs of Ubuntu/Debian
type Bolt struct {
Path string
Log *logrus.Entry
db *bolt.DB
}
// SetupBolt opens a boltdb and creates a meta bucket if not exists.
func SetupBolt(path string, l *logrus.Entry) error {
l.Infof("Open boltDB: %s", path)
db, err := bolt.Open(path, 0600, nil)
if err != nil {
return err
}
b := Bolt{
Path: path,
Log: l,
db: db,
}
if err = b.createBucketIfNotExists(metabucket); err != nil {
return err
}
DB = b
return nil
}
// Close a db.
func (b Bolt) Close() error {
if b.db == nil {
return nil
}
return b.db.Close()
}
// CreateBucketIfNotExists creates a buket that is specified by arg.
func (b *Bolt) createBucketIfNotExists(name string) error {
return b.db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(name))
if err != nil {
return xerrors.Errorf("Failed to create bucket: %w", err)
}
return nil
})
}
// GetMeta gets a Meta Information os the servername to boltdb.
func (b Bolt) GetMeta(serverName string) (meta Meta, found bool, err error) {
err = b.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket([]byte(metabucket))
v := bkt.Get([]byte(serverName))
if len(v) == 0 {
found = false
return nil
}
if e := json.Unmarshal(v, &meta); e != nil {
return e
}
found = true
return nil
})
return
}
// RefreshMeta gets a Meta Information os the servername to boltdb.
func (b Bolt) RefreshMeta(meta Meta) error {
meta.CreatedAt = time.Now()
jsonBytes, err := json.Marshal(meta)
if err != nil {
return xerrors.Errorf("Failed to marshal to JSON: %w", err)
}
return b.db.Update(func(tx *bolt.Tx) error {
bkt := tx.Bucket([]byte(metabucket))
if err := bkt.Put([]byte(meta.Name), jsonBytes); err != nil {
return err
}
b.Log.Debugf("Refreshed Meta: %s", meta.Name)
return nil
})
}
// EnsureBuckets puts a Meta information and create a buket that holds changelogs.
func (b Bolt) EnsureBuckets(meta Meta) error {
jsonBytes, err := json.Marshal(meta)
if err != nil {
return xerrors.Errorf("Failed to marshal to JSON: %w", err)
}
return b.db.Update(func(tx *bolt.Tx) error {
b.Log.Debugf("Put to meta: %s", meta.Name)
bkt := tx.Bucket([]byte(metabucket))
if err := bkt.Put([]byte(meta.Name), jsonBytes); err != nil {
return err
}
// re-create a bucket (bucket name: servername)
bkt = tx.Bucket([]byte(meta.Name))
if bkt != nil {
b.Log.Debugf("Delete bucket: %s", meta.Name)
if err := tx.DeleteBucket([]byte(meta.Name)); err != nil {
return err
}
b.Log.Debugf("Bucket deleted: %s", meta.Name)
}
b.Log.Debugf("Create bucket: %s", meta.Name)
if _, err := tx.CreateBucket([]byte(meta.Name)); err != nil {
return err
}
b.Log.Debugf("Bucket created: %s", meta.Name)
return nil
})
}
// PrettyPrint is for debug
func (b Bolt) PrettyPrint(meta Meta) error {
return b.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket([]byte(metabucket))
v := bkt.Get([]byte(meta.Name))
b.Log.Debugf("Meta: key:%s, value:%s", meta.Name, v)
bkt = tx.Bucket([]byte(meta.Name))
c := bkt.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
b.Log.Debugf("key:%s, len: %d, %s...",
k, len(v), util.Truncate(string(v), 30))
}
return nil
})
}
// GetChangelog get the changelog of specified packName from the Bucket
func (b Bolt) GetChangelog(servername, packName string) (changelog string, err error) {
err = b.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket([]byte(servername))
if bkt == nil {
return xerrors.Errorf("Failed to get Bucket: %s", servername)
}
v := bkt.Get([]byte(packName))
if v == nil {
changelog = ""
return nil
}
changelog = string(v)
return nil
})
return
}
// PutChangelog put the changelgo of specified packName into the Bucket
func (b Bolt) PutChangelog(servername, packName, changelog string) error {
return b.db.Update(func(tx *bolt.Tx) error {
bkt := tx.Bucket([]byte(servername))
if bkt == nil {
return xerrors.Errorf("Failed to get Bucket: %s", servername)
}
return bkt.Put([]byte(packName), []byte(changelog))
})
}

120
cache/bolt_test.go vendored
View File

@@ -1,120 +0,0 @@
package cache
import (
"os"
"reflect"
"testing"
"github.com/boltdb/bolt"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/sirupsen/logrus"
)
const path = "/tmp/vuls-test-cache-11111111.db"
const servername = "server1"
var meta = Meta{
Name: servername,
Distro: config.Distro{
Family: "ubuntu",
Release: "16.04",
},
Packs: models.Packages{
"apt": {
Name: "apt",
Version: "1",
},
},
}
func TestSetupBolt(t *testing.T) {
log := logrus.NewEntry(&logrus.Logger{})
err := SetupBolt(path, log)
if err != nil {
t.Errorf("Failed to setup bolt: %s", err)
}
defer os.Remove(path)
if err := DB.Close(); err != nil {
t.Errorf("Failed to close bolt: %s", err)
}
// check if meta bucket exists
db, err := bolt.Open(path, 0600, nil)
if err != nil {
t.Errorf("Failed to open bolt: %s", err)
}
_ = db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket([]byte(metabucket))
if bkt == nil {
t.Errorf("Meta bucket nof found")
}
return nil
})
}
func TestEnsureBuckets(t *testing.T) {
log := logrus.NewEntry(&logrus.Logger{})
if err := SetupBolt(path, log); err != nil {
t.Errorf("Failed to setup bolt: %s", err)
}
if err := DB.EnsureBuckets(meta); err != nil {
t.Errorf("Failed to ensure buckets: %s", err)
}
defer os.Remove(path)
m, found, err := DB.GetMeta(servername)
if err != nil {
t.Errorf("Failed to get meta: %s", err)
}
if !found {
t.Errorf("Not Found in meta")
}
if meta.Name != m.Name || meta.Distro != m.Distro {
t.Errorf("expected %v, actual %v", meta, m)
}
if !reflect.DeepEqual(meta.Packs, m.Packs) {
t.Errorf("expected %v, actual %v", meta.Packs, m.Packs)
}
if err := DB.Close(); err != nil {
t.Errorf("Failed to close bolt: %s", err)
}
db, err := bolt.Open(path, 0600, nil)
if err != nil {
t.Errorf("Failed to open bolt: %s", err)
}
_ = db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket([]byte(servername))
if bkt == nil {
t.Errorf("Meta bucket nof found")
}
return nil
})
}
func TestPutGetChangelog(t *testing.T) {
clog := "changelog-text"
log := logrus.NewEntry(&logrus.Logger{})
if err := SetupBolt(path, log); err != nil {
t.Errorf("Failed to setup bolt: %s", err)
}
defer os.Remove(path)
if err := DB.EnsureBuckets(meta); err != nil {
t.Errorf("Failed to ensure buckets: %s", err)
}
if err := DB.PutChangelog(servername, "apt", clog); err != nil {
t.Errorf("Failed to put changelog: %s", err)
}
if actual, err := DB.GetChangelog(servername, "apt"); err != nil {
t.Errorf("Failed to get changelog: %s", err)
} else {
if actual != clog {
t.Errorf("changelog is not same. e: %s, a: %s", clog, actual)
}
}
}

33
cache/db.go vendored
View File

@@ -1,33 +0,0 @@
package cache
import (
"time"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
)
// DB has a cache instance
var DB Cache
const metabucket = "changelog-meta"
// Cache is a interface of cache
type Cache interface {
Close() error
GetMeta(string) (Meta, bool, error)
RefreshMeta(Meta) error
EnsureBuckets(Meta) error
PrettyPrint(Meta) error
GetChangelog(string, string) (string, error)
PutChangelog(string, string, string) error
}
// Meta holds a server name, distro information of the scanned server and
// package information that was collected at the last scan.
type Meta struct {
Name string
Distro config.Distro
Packs models.Packages
CreatedAt time.Time
}

15
cmd/vuls/main.go Normal file
View File

@@ -0,0 +1,15 @@
package main
import (
"fmt"
"os"
"github.com/future-architect/vuls/pkg/cmd/root"
)
func main() {
if err := root.NewCmdRoot().Execute(); err != nil {
fmt.Fprintf(os.Stderr, "failed to exec vuls: %s\n", fmt.Sprintf("%+v", err))
os.Exit(1)
}
}

View File

@@ -1,173 +0,0 @@
package commands
import (
"context"
"flag"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/google/subcommands"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/scan"
"github.com/future-architect/vuls/util"
)
// ConfigtestCmd is Subcommand
type ConfigtestCmd struct {
configPath string
askKeyPassword bool
timeoutSec int
}
// Name return subcommand name
func (*ConfigtestCmd) Name() string { return "configtest" }
// Synopsis return synopsis
func (*ConfigtestCmd) Synopsis() string { return "Test configuration" }
// Usage return usage
func (*ConfigtestCmd) Usage() string {
return `configtest:
configtest
[-config=/path/to/config.toml]
[-log-dir=/path/to/log]
[-ask-key-password]
[-timeout=300]
[-ssh-config]
[-containers-only]
[-http-proxy=http://192.168.0.1:8080]
[-debug]
[-vvv]
[SERVER]...
`
}
// SetFlags set flag
func (p *ConfigtestCmd) SetFlags(f *flag.FlagSet) {
wd, _ := os.Getwd()
defaultConfPath := filepath.Join(wd, "config.toml")
f.StringVar(&p.configPath, "config", defaultConfPath, "/path/to/toml")
defaultLogDir := util.GetDefaultLogDir()
f.StringVar(&c.Conf.LogDir, "log-dir", defaultLogDir, "/path/to/log")
f.BoolVar(&c.Conf.Debug, "debug", false, "debug mode")
f.IntVar(&p.timeoutSec, "timeout", 5*60, "Timeout(Sec)")
f.BoolVar(&p.askKeyPassword, "ask-key-password", false,
"Ask ssh privatekey password before scanning",
)
f.StringVar(&c.Conf.HTTPProxy, "http-proxy", "",
"http://proxy-url:port (default: empty)")
f.BoolVar(&c.Conf.SSHNative, "ssh-native-insecure", false,
"Use Native Go implementation of SSH. Default: Use the external command")
f.BoolVar(&c.Conf.SSHConfig, "ssh-config", false,
"[Deprecated] Use SSH options specified in ssh_config preferentially")
f.BoolVar(&c.Conf.ContainersOnly, "containers-only", false,
"Test containers only. Default: Test both of hosts and containers")
f.BoolVar(&c.Conf.Vvv, "vvv", false, "ssh -vvv")
}
// Execute execute
func (p *ConfigtestCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
util.Log = util.NewCustomLogger(c.ServerInfo{})
if err := mkdirDotVuls(); err != nil {
util.Log.Errorf("Failed to create .vuls. err: %+v", err)
return subcommands.ExitUsageError
}
var keyPass string
var err error
if p.askKeyPassword {
prompt := "SSH key password: "
if keyPass, err = getPasswd(prompt); err != nil {
util.Log.Error(err)
return subcommands.ExitFailure
}
}
err = c.Load(p.configPath, keyPass)
if err != nil {
msg := []string{
fmt.Sprintf("Error loading %s", p.configPath),
"If you update Vuls and get this error, there may be incompatible changes in config.toml",
"Please check config.toml template : https://vuls.io/docs/en/usage-settings.html",
}
util.Log.Errorf("%s\n%+v", strings.Join(msg, "\n"), err)
return subcommands.ExitUsageError
}
if c.Conf.SSHConfig {
msg := []string{
"-ssh-config is deprecated",
"If you update Vuls and get this error, there may be incompatible changes in config.toml",
"Please check config.toml template : https://vuls.io/docs/en/usage-settings.html",
}
util.Log.Errorf("%s", strings.Join(msg, "\n"))
return subcommands.ExitUsageError
}
var servernames []string
if 0 < len(f.Args()) {
servernames = f.Args()
}
target := make(map[string]c.ServerInfo)
for _, arg := range servernames {
found := false
for servername, info := range c.Conf.Servers {
if servername == arg {
target[servername] = info
found = true
break
}
}
if !found {
util.Log.Errorf("%s is not in config", arg)
return subcommands.ExitUsageError
}
}
if 0 < len(servernames) {
c.Conf.Servers = target
}
util.Log.Info("Validating config...")
if !c.Conf.ValidateOnConfigtest() {
return subcommands.ExitUsageError
}
util.Log.Info("Detecting Server/Container OS... ")
if err := scan.InitServers(p.timeoutSec); err != nil {
util.Log.Errorf("Failed to init servers. err: %+v", err)
return subcommands.ExitFailure
}
util.Log.Info("Checking Scan Modes...")
if err := scan.CheckScanModes(); err != nil {
util.Log.Errorf("Fix config.toml. err: %+v", err)
return subcommands.ExitFailure
}
util.Log.Info("Checking dependencies...")
scan.CheckDependencies(p.timeoutSec)
util.Log.Info("Checking sudo settings...")
scan.CheckIfSudoNoPasswd(p.timeoutSec)
util.Log.Info("It can be scanned with fast scan mode even if warn or err messages are displayed due to lack of dependent packages or sudo settings in fast-root or deep scan mode")
if scan.PrintSSHableServerNames() {
return subcommands.ExitSuccess
}
return subcommands.ExitFailure
}

View File

@@ -1,252 +0,0 @@
package commands
import (
"context"
"flag"
"fmt"
"os"
"strings"
"text/template"
"github.com/google/subcommands"
ps "github.com/kotakanbe/go-pingscanner"
"github.com/sirupsen/logrus"
)
// DiscoverCmd is Subcommand of host discovery mode
type DiscoverCmd struct {
}
// Name return subcommand name
func (*DiscoverCmd) Name() string { return "discover" }
// Synopsis return synopsis
func (*DiscoverCmd) Synopsis() string { return "Host discovery in the CIDR" }
// Usage return usage
func (*DiscoverCmd) Usage() string {
return `discover:
discover 192.168.0.0/24
`
}
// SetFlags set flag
func (p *DiscoverCmd) SetFlags(f *flag.FlagSet) {
}
// Execute execute
func (p *DiscoverCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
// validate
if len(f.Args()) == 0 {
logrus.Errorf("Usage: " + p.Usage())
return subcommands.ExitUsageError
}
for _, cidr := range f.Args() {
scanner := ps.PingScanner{
CIDR: cidr,
PingOptions: []string{
"-c1",
},
NumOfConcurrency: 100,
}
hosts, err := scanner.Scan()
if err != nil {
logrus.Errorf("Host Discovery failed. err: %s", err)
return subcommands.ExitFailure
}
if len(hosts) < 1 {
logrus.Errorf("Active hosts not found in %s", cidr)
return subcommands.ExitSuccess
} else if err := printConfigToml(hosts); err != nil {
logrus.Errorf("Failed to parse template. err: %s", err)
return subcommands.ExitFailure
}
}
return subcommands.ExitSuccess
}
// Output the template of config.toml
func printConfigToml(ips []string) (err error) {
const tomlTemplate = `
# https://vuls.io/docs/en/usage-settings.html
[cveDict]
type = "sqlite3"
sqlite3Path = "/path/to/cve.sqlite3"
#url = ""
[ovalDict]
type = "sqlite3"
sqlite3Path = "/path/to/oval.sqlite3"
#url = ""
[gost]
type = "sqlite3"
sqlite3Path = "/path/to/gost.sqlite3"
#url = ""
[exploit]
type = "sqlite3"
sqlite3Path = "/path/to/go-exploitdb.sqlite3"
#url = ""
[metasploit]
type = "sqlite3"
sqlite3Path = "/path/to/go-msfdb.sqlite3"
#url = ""
# https://vuls.io/docs/en/usage-settings.html#slack-section
#[slack]
#hookURL = "https://hooks.slack.com/services/abc123/defghijklmnopqrstuvwxyz"
##legacyToken = "xoxp-11111111111-222222222222-3333333333"
#channel = "#channel-name"
##channel = "${servername}"
#iconEmoji = ":ghost:"
#authUser = "username"
#notifyUsers = ["@username"]
# https://vuls.io/docs/en/usage-settings.html#email-section
#[email]
#smtpAddr = "smtp.example.com"
#smtpPort = "587"
#user = "username"
#password = "password"
#from = "from@example.com"
#to = ["to@example.com"]
#cc = ["cc@example.com"]
#subjectPrefix = "[vuls]"
# https://vuls.io/docs/en/usage-settings.html#http-section
#[http]
#url = "http://localhost:11234"
# https://vuls.io/docs/en/usage-settings.html#syslog-section
#[syslog]
#protocol = "tcp"
#host = "localhost"
#port = "514"
#tag = "vuls"
#facility = "local0"
#severity = "alert"
#verbose = false
# https://vuls.io/docs/en/usage-report.html#example-put-results-in-s3-bucket
#[aws]
#profile = "default"
#region = "ap-northeast-1"
#s3Bucket = "vuls"
#s3ResultsDir = "/path/to/result"
#s3ServerSideEncryption = "AES256"
# https://vuls.io/docs/en/usage-report.html#example-put-results-in-azure-blob-storage<Paste>
#[azure]
#accountName = "default"
#accountKey = "xxxxxxxxxxxxxx"
#containerName = "vuls"
# https://vuls.io/docs/en/usage-settings.html#stride-section
#[stride]
#hookURL = "xxxxxxxxxxxxxxx"
#authToken = "xxxxxxxxxxxxxx"
# https://vuls.io/docs/en/usage-settings.html#hipchat-section
#[hipchat]
#room = "vuls"
#authToken = "xxxxxxxxxxxxxx"
# https://vuls.io/docs/en/usage-settings.html#chatwork-section
#[chatwork]
#room = "xxxxxxxxxxx"
#apiToken = "xxxxxxxxxxxxxxxxxx"
# https://vuls.io/docs/en/usage-settings.html#telegram-section
#[telegram]
#chatID = "xxxxxxxxxxx"
#token = "xxxxxxxxxxxxxxxxxx"
# https://vuls.io/docs/en/usage-settings.html#default-section
[default]
#port = "22"
#user = "username"
#keyPath = "/home/username/.ssh/id_rsa"
#scanMode = ["fast", "fast-root", "deep", "offline"]
#cpeNames = [
# "cpe:/a:rubyonrails:ruby_on_rails:4.2.1",
#]
#owaspDCXMLPath = "/tmp/dependency-check-report.xml"
#ignoreCves = ["CVE-2014-6271"]
#containerType = "docker" #or "lxd" or "lxc" default: docker
#containersIncluded = ["${running}"]
#containersExcluded = ["container_name_a"]
# https://vuls.io/docs/en/usage-settings.html#servers-section
[servers]
{{- $names:= .Names}}
{{range $i, $ip := .IPs}}
[servers.{{index $names $i}}]
host = "{{$ip}}"
#port = "22"
#user = "root"
#sshConfigPath = "/home/username/.ssh/config"
#keyPath = "/home/username/.ssh/id_rsa"
#scanMode = ["fast", "fast-root", "deep", "offline"]
#type = "pseudo"
#memo = "DB Server"
#cpeNames = [ "cpe:/a:rubyonrails:ruby_on_rails:4.2.1" ]
#owaspDCXMLPath = "/path/to/dependency-check-report.xml"
#ignoreCves = ["CVE-2014-0160"]
#containerType = "docker" #or "lxd" or "lxc" default: docker
#containersIncluded = ["${running}"]
#containersExcluded = ["container_name_a"]
#[servers.{{index $names $i}}.containers.container_name_a]
#cpeNames = [ "cpe:/a:rubyonrails:ruby_on_rails:4.2.1" ]
#owaspDCXMLPath = "/path/to/dependency-check-report.xml"
#ignoreCves = ["CVE-2014-0160"]
#[servers.{{index $names $i}}.githubs."owner/repo"]
#token = "yourToken"
#[servers.{{index $names $i}}.wordpress]
#cmdPath = "/usr/local/bin/wp"
#osUser = "wordpress"
#docRoot = "/path/to/DocumentRoot/"
#wpVulnDBToken = "xxxxTokenxxxx"
#ignoreInactive = true
#[servers.{{index $names $i}}.optional]
#key = "value1"
{{end}}
`
var tpl *template.Template
if tpl, err = template.New("template").Parse(tomlTemplate); err != nil {
return
}
type activeHosts struct {
IPs []string
Names []string
}
a := activeHosts{IPs: ips}
names := []string{}
for _, ip := range ips {
// TOML section header must not contain "."
name := strings.Replace(ip, ".", "-", -1)
names = append(names, name)
}
a.Names = names
fmt.Println("# Create config.toml using below and then ./vuls -config=/path/to/config.toml")
if err = tpl.Execute(os.Stdout, a); err != nil {
return
}
return
}

View File

@@ -1,74 +0,0 @@
package commands
import (
"context"
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/report"
"github.com/google/subcommands"
)
// HistoryCmd is Subcommand of list scanned results
type HistoryCmd struct{}
// Name return subcommand name
func (*HistoryCmd) Name() string { return "history" }
// Synopsis return synopsis
func (*HistoryCmd) Synopsis() string {
return `List history of scanning.`
}
// Usage return usage
func (*HistoryCmd) Usage() string {
return `history:
history
[-results-dir=/path/to/results]
`
}
// SetFlags set flag
func (p *HistoryCmd) SetFlags(f *flag.FlagSet) {
f.BoolVar(&c.Conf.DebugSQL, "debug-sql", false, "SQL debug mode")
wd, _ := os.Getwd()
defaultResultsDir := filepath.Join(wd, "results")
f.StringVar(&c.Conf.ResultsDir, "results-dir", defaultResultsDir, "/path/to/results")
}
// Execute execute
func (p *HistoryCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
dirs, err := report.ListValidJSONDirs()
if err != nil {
return subcommands.ExitFailure
}
for _, d := range dirs {
var files []os.FileInfo
if files, err = ioutil.ReadDir(d); err != nil {
return subcommands.ExitFailure
}
var hosts []string
for _, f := range files {
if filepath.Ext(f.Name()) != ".json" {
continue
}
fileBase := strings.TrimSuffix(f.Name(), filepath.Ext(f.Name()))
hosts = append(hosts, fileBase)
}
splitPath := strings.Split(d, string(os.PathSeparator))
timeStr := splitPath[len(splitPath)-1]
fmt.Printf("%s %d servers: %s\n",
timeStr,
len(hosts),
strings.Join(hosts, ", "),
)
}
return subcommands.ExitSuccess
}

View File

@@ -1,452 +0,0 @@
package commands
import (
"context"
"flag"
"os"
"path/filepath"
"github.com/aquasecurity/trivy/pkg/utils"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/exploit"
"github.com/future-architect/vuls/gost"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/msf"
"github.com/future-architect/vuls/oval"
"github.com/future-architect/vuls/report"
"github.com/future-architect/vuls/util"
"github.com/google/subcommands"
"github.com/k0kubun/pp"
)
// ReportCmd is subcommand for reporting
type ReportCmd struct {
configPath string
cveDict c.GoCveDictConf
ovalDict c.GovalDictConf
gostConf c.GostConf
exploitConf c.ExploitConf
metasploitConf c.MetasploitConf
httpConf c.HTTPConf
}
// 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-dir=/path/to/log]
[-refresh-cve]
[-cvss-over=7]
[-diff]
[-wp-ignore-inactive]
[-ignore-unscored-cves]
[-ignore-unfixed]
[-ignore-github-dismissed]
[-to-email]
[-to-http]
[-to-slack]
[-to-stride]
[-to-hipchat]
[-to-chatwork]
[-to-telegram]
[-to-localfile]
[-to-s3]
[-to-azure-blob]
[-to-saas]
[-format-json]
[-format-xml]
[-format-one-email]
[-format-one-line-text]
[-format-list]
[-format-full-text]
[-gzip]
[-uuid]
[-http-proxy=http://192.168.0.1:8080]
[-debug]
[-debug-sql]
[-quiet]
[-no-progress]
[-pipe]
[-cvedb-type=sqlite3|mysql|postgres|redis|http]
[-cvedb-sqlite3-path=/path/to/cve.sqlite3]
[-cvedb-url=http://127.0.0.1:1323 or DB connection string]
[-ovaldb-type=sqlite3|mysql|redis|http]
[-ovaldb-sqlite3-path=/path/to/oval.sqlite3]
[-ovaldb-url=http://127.0.0.1:1324 or DB connection string]
[-gostdb-type=sqlite3|mysql|redis|http]
[-gostdb-sqlite3-path=/path/to/gost.sqlite3]
[-gostdb-url=http://127.0.0.1:1325 or DB connection string]
[-exploitdb-type=sqlite3|mysql|redis|http]
[-exploitdb-sqlite3-path=/path/to/exploitdb.sqlite3]
[-exploitdb-url=http://127.0.0.1:1326 or DB connection string]
[-msfdb-type=sqlite3|mysql|redis|http]
[-msfdb-sqlite3-path=/path/to/msfdb.sqlite3]
[-msfdb-url=http://127.0.0.1:1327 or DB connection string]
[-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(&c.Conf.Lang, "lang", "en", "[en|ja]")
f.BoolVar(&c.Conf.Debug, "debug", false, "debug mode")
f.BoolVar(&c.Conf.DebugSQL, "debug-sql", false, "SQL debug mode")
f.BoolVar(&c.Conf.Quiet, "quiet", false, "Quiet mode. No output on stdout")
f.BoolVar(&c.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(&c.Conf.ResultsDir, "results-dir", defaultResultsDir, "/path/to/results")
defaultLogDir := util.GetDefaultLogDir()
f.StringVar(&c.Conf.LogDir, "log-dir", defaultLogDir, "/path/to/log")
f.BoolVar(&c.Conf.RefreshCve, "refresh-cve", false,
"Refresh CVE information in JSON file under results dir")
f.Float64Var(&c.Conf.CvssScoreOver, "cvss-over", 0,
"-cvss-over=6.5 means reporting CVSS Score 6.5 and over (default: 0 (means report all))")
f.BoolVar(&c.Conf.Diff, "diff", false,
"Difference between previous result and current result ")
f.BoolVar(&c.Conf.WpIgnoreInactive, "wp-ignore-inactive", false,
"ignore inactive on wordpress's plugin and theme")
f.BoolVar(&c.Conf.IgnoreUnscoredCves, "ignore-unscored-cves", false,
"Don't report the unscored CVEs")
f.BoolVar(&c.Conf.IgnoreUnfixed, "ignore-unfixed", false,
"Don't report the unfixed CVEs")
f.BoolVar(&c.Conf.IgnoreGitHubDismissed, "ignore-github-dismissed", false,
"Don't report the dismissed CVEs on GitHub Security Alerts")
f.StringVar(
&c.Conf.HTTPProxy, "http-proxy", "",
"http://proxy-url:port (default: empty)")
f.BoolVar(&c.Conf.FormatJSON, "format-json", false, "JSON format")
f.BoolVar(&c.Conf.FormatXML, "format-xml", false, "XML format")
f.BoolVar(&c.Conf.FormatOneEMail, "format-one-email", false,
"Send all the host report via only one EMail (Specify with -to-email)")
f.BoolVar(&c.Conf.FormatOneLineText, "format-one-line-text", false,
"One line summary in plain text")
f.BoolVar(&c.Conf.FormatList, "format-list", false, "Display as list format")
f.BoolVar(&c.Conf.FormatFullText, "format-full-text", false,
"Detail report in plain text")
f.BoolVar(&c.Conf.ToSlack, "to-slack", false, "Send report via Slack")
f.BoolVar(&c.Conf.ToStride, "to-stride", false, "Send report via Stride")
f.BoolVar(&c.Conf.ToHipChat, "to-hipchat", false, "Send report via hipchat")
f.BoolVar(&c.Conf.ToChatWork, "to-chatwork", false, "Send report via chatwork")
f.BoolVar(&c.Conf.ToTelegram, "to-telegram", false, "Send report via Telegram")
f.BoolVar(&c.Conf.ToEmail, "to-email", false, "Send report via Email")
f.BoolVar(&c.Conf.ToSyslog, "to-syslog", false, "Send report via Syslog")
f.BoolVar(&c.Conf.ToLocalFile, "to-localfile", false, "Write report to localfile")
f.BoolVar(&c.Conf.ToS3, "to-s3", false,
"Write report to S3 (bucket/yyyyMMdd_HHmm/servername.json/xml/txt)")
f.BoolVar(&c.Conf.ToHTTP, "to-http", false, "Send report via HTTP POST")
f.BoolVar(&c.Conf.ToAzureBlob, "to-azure-blob", false,
"Write report to Azure Storage blob (container/yyyyMMdd_HHmm/servername.json/xml/txt)")
f.BoolVar(&c.Conf.ToSaas, "to-saas", false,
"Upload report to Future Vuls(https://vuls.biz/) before report")
f.BoolVar(&c.Conf.GZIP, "gzip", false, "gzip compression")
f.BoolVar(&c.Conf.UUID, "uuid", false,
"Auto generate of scan target servers and then write to config.toml and scan result")
f.BoolVar(&c.Conf.Pipe, "pipe", false, "Use args passed via PIPE")
f.StringVar(&p.cveDict.Type, "cvedb-type", "",
"DB type of go-cve-dictionary (sqlite3, mysql, postgres, redis or http)")
f.StringVar(&p.cveDict.SQLite3Path, "cvedb-sqlite3-path", "", "/path/to/sqlite3")
f.StringVar(&p.cveDict.URL, "cvedb-url", "",
"http://go-cve-dictionary.com:1323 or DB connection string")
f.StringVar(&p.ovalDict.Type, "ovaldb-type", "",
"DB type of goval-dictionary (sqlite3, mysql, postgres, redis or http)")
f.StringVar(&p.ovalDict.SQLite3Path, "ovaldb-sqlite3-path", "", "/path/to/sqlite3")
f.StringVar(&p.ovalDict.URL, "ovaldb-url", "",
"http://goval-dictionary.com:1324 or DB connection string")
f.StringVar(&p.gostConf.Type, "gostdb-type", "",
"DB type of gost (sqlite3, mysql, postgres, redis or http)")
f.StringVar(&p.gostConf.SQLite3Path, "gostdb-sqlite3-path", "", "/path/to/sqlite3")
f.StringVar(&p.gostConf.URL, "gostdb-url", "",
"http://gost.com:1325 or DB connection string")
f.StringVar(&p.exploitConf.Type, "exploitdb-type", "",
"DB type of exploit (sqlite3, mysql, postgres, redis or http)")
f.StringVar(&p.exploitConf.SQLite3Path, "exploitdb-sqlite3-path", "", "/path/to/sqlite3")
f.StringVar(&p.exploitConf.URL, "exploitdb-url", "",
"http://exploit.com:1326 or DB connection string")
f.StringVar(&p.metasploitConf.Type, "msfdb-type", "",
"DB type of msf (sqlite3, mysql, postgres, redis or http)")
f.StringVar(&p.metasploitConf.SQLite3Path, "msfdb-sqlite3-path", "", "/path/to/sqlite3")
f.StringVar(&p.metasploitConf.URL, "msfdb-url", "",
"http://metasploit.com:1327 or DB connection string")
f.StringVar(&p.httpConf.URL, "http", "", "-to-http http://vuls-report")
f.StringVar(&c.Conf.TrivyCacheDBDir, "trivy-cachedb-dir",
utils.DefaultCacheDir(), "/path/to/dir")
}
// Execute execute
func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
util.Log = util.NewCustomLogger(c.ServerInfo{})
if err := c.Load(p.configPath, ""); err != nil {
util.Log.Errorf("Error loading %s, %+v", p.configPath, err)
return subcommands.ExitUsageError
}
c.Conf.CveDict.Overwrite(p.cveDict)
c.Conf.OvalDict.Overwrite(p.ovalDict)
c.Conf.Gost.Overwrite(p.gostConf)
c.Conf.Exploit.Overwrite(p.exploitConf)
c.Conf.Metasploit.Overwrite(p.metasploitConf)
c.Conf.HTTP.Overwrite(p.httpConf)
var dir string
var err error
if c.Conf.Diff {
dir, err = report.JSONDir([]string{})
} else {
dir, err = report.JSONDir(f.Args())
}
if err != nil {
util.Log.Errorf("Failed to read from JSON: %+v", err)
return subcommands.ExitFailure
}
// report
reports := []report.ResultWriter{
report.StdoutWriter{},
}
if c.Conf.ToSlack {
reports = append(reports, report.SlackWriter{})
}
if c.Conf.ToStride {
reports = append(reports, report.StrideWriter{})
}
if c.Conf.ToHipChat {
reports = append(reports, report.HipChatWriter{})
}
if c.Conf.ToChatWork {
reports = append(reports, report.ChatWorkWriter{})
}
if c.Conf.ToTelegram {
reports = append(reports, report.TelegramWriter{})
}
if c.Conf.ToEmail {
reports = append(reports, report.EMailWriter{})
}
if c.Conf.ToSyslog {
reports = append(reports, report.SyslogWriter{})
}
if c.Conf.ToHTTP {
reports = append(reports, report.HTTPRequestWriter{})
}
if c.Conf.ToLocalFile {
reports = append(reports, report.LocalFileWriter{
CurrentDir: dir,
})
}
if c.Conf.ToS3 {
if err := report.CheckIfBucketExists(); err != nil {
util.Log.Errorf("Check if there is a bucket beforehand: %s, err: %+v",
c.Conf.AWS.S3Bucket, err)
return subcommands.ExitUsageError
}
reports = append(reports, report.S3Writer{})
}
if c.Conf.ToAzureBlob {
if len(c.Conf.Azure.AccountName) == 0 {
c.Conf.Azure.AccountName = os.Getenv("AZURE_STORAGE_ACCOUNT")
}
if len(c.Conf.Azure.AccountKey) == 0 {
c.Conf.Azure.AccountKey = os.Getenv("AZURE_STORAGE_ACCESS_KEY")
}
if len(c.Conf.Azure.ContainerName) == 0 {
util.Log.Error("Azure storage container name is required with -azure-container option")
return subcommands.ExitUsageError
}
if err := report.CheckIfAzureContainerExists(); err != nil {
util.Log.Errorf("Check if there is a container beforehand: %s, err: %+v",
c.Conf.Azure.ContainerName, err)
return subcommands.ExitUsageError
}
reports = append(reports, report.AzureBlobWriter{})
}
if c.Conf.ToSaas {
if !c.Conf.UUID {
util.Log.Errorf("If you use the -to-saas option, you need to enable the uuid option")
return subcommands.ExitUsageError
}
reports = append(reports, report.SaasWriter{})
}
if !(c.Conf.FormatJSON || c.Conf.FormatOneLineText ||
c.Conf.FormatList || c.Conf.FormatFullText || c.Conf.FormatXML) {
c.Conf.FormatList = true
}
util.Log.Info("Validating config...")
if !c.Conf.ValidateOnReport() {
return subcommands.ExitUsageError
}
var loaded models.ScanResults
if loaded, err = report.LoadScanResults(dir); err != nil {
util.Log.Error(err)
return subcommands.ExitFailure
}
util.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 {
util.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 {
util.Log.Debugf("%s: %s",
r.ServerInfo(),
pp.Sprintf("%s", c.Conf.Servers[r.ServerName]))
}
if c.Conf.UUID {
// Ensure UUIDs of scan target servers in config.toml
if err := report.EnsureUUIDs(p.configPath, res); err != nil {
util.Log.Errorf("Failed to ensure UUIDs. err: %+v", err)
return subcommands.ExitFailure
}
}
if !c.Conf.ToSaas {
util.Log.Info("Validating db config...")
if !c.Conf.ValidateOnReportDB() {
return subcommands.ExitUsageError
}
if c.Conf.CveDict.URL != "" {
if err := report.CveClient.CheckHealth(); err != nil {
util.Log.Errorf("CVE HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-cve-dictionary as server mode before reporting or run with `-cvedb-type=sqlite3 -cvedb-sqlite3-path` option instead of -cvedb-url")
return subcommands.ExitFailure
}
}
if c.Conf.OvalDict.URL != "" {
err := oval.Base{}.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("OVAL HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run goval-dictionary as server mode before reporting or run with `-ovaldb-type=sqlite3 -ovaldb-sqlite3-path` option instead of -ovaldb-url")
return subcommands.ExitFailure
}
}
if c.Conf.Gost.URL != "" {
util.Log.Infof("gost: %s", c.Conf.Gost.URL)
err := gost.Base{}.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("gost HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run gost as server mode before reporting or run with `-gostdb-type=sqlite3 -gostdb-sqlite3-path` option instead of -gostdb-url")
return subcommands.ExitFailure
}
}
if c.Conf.Exploit.URL != "" {
err := exploit.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("exploit HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-exploitdb as server mode before reporting")
return subcommands.ExitFailure
}
}
if c.Conf.Metasploit.URL != "" {
err := msf.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("metasploit HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-msfdb as server mode before reporting")
return subcommands.ExitFailure
}
}
dbclient, locked, err := report.NewDBClient(report.DBClientConf{
CveDictCnf: c.Conf.CveDict,
OvalDictCnf: c.Conf.OvalDict,
GostCnf: c.Conf.Gost,
ExploitCnf: c.Conf.Exploit,
MetasploitCnf: c.Conf.Metasploit,
DebugSQL: c.Conf.DebugSQL,
})
if locked {
util.Log.Errorf("SQLite3 is locked. Close other DB connections and try again. err: %+v", err)
return subcommands.ExitFailure
}
if err != nil {
util.Log.Errorf("Failed to init DB Clients. err: %+v", err)
return subcommands.ExitFailure
}
defer dbclient.CloseDB()
if res, err = report.FillCveInfos(*dbclient, res, dir); err != nil {
util.Log.Errorf("%+v", err)
return subcommands.ExitFailure
}
}
for _, w := range reports {
if err := w.Write(res...); err != nil {
util.Log.Errorf("Failed to report. err: %+v", err)
return subcommands.ExitFailure
}
}
if hasError {
return subcommands.ExitFailure
}
return subcommands.ExitSuccess
}

View File

@@ -1,231 +0,0 @@
package commands
import (
"context"
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/scan"
"github.com/future-architect/vuls/util"
"github.com/google/subcommands"
"github.com/k0kubun/pp"
)
// ScanCmd is Subcommand of host discovery mode
type ScanCmd struct {
configPath string
askKeyPassword bool
timeoutSec int
scanTimeoutSec int
}
// Name return subcommand name
func (*ScanCmd) Name() string { return "scan" }
// Synopsis return synopsis
func (*ScanCmd) Synopsis() string { return "Scan vulnerabilities" }
// Usage return usage
func (*ScanCmd) Usage() string {
return `scan:
scan
[-config=/path/to/config.toml]
[-results-dir=/path/to/results]
[-log-dir=/path/to/log]
[-cachedb-path=/path/to/cache.db]
[-ssh-native-insecure]
[-ssh-config]
[-containers-only]
[-libs-only]
[-wordpress-only]
[-skip-broken]
[-http-proxy=http://192.168.0.1:8080]
[-ask-key-password]
[-timeout=300]
[-timeout-scan=7200]
[-debug]
[-quiet]
[-pipe]
[-vvv]
[-ips]
[SERVER]...
`
}
// SetFlags set flag
func (p *ScanCmd) SetFlags(f *flag.FlagSet) {
f.BoolVar(&c.Conf.Debug, "debug", false, "debug mode")
f.BoolVar(&c.Conf.Quiet, "quiet", false, "Quiet mode. No output on stdout")
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(&c.Conf.ResultsDir, "results-dir", defaultResultsDir, "/path/to/results")
defaultLogDir := util.GetDefaultLogDir()
f.StringVar(&c.Conf.LogDir, "log-dir", defaultLogDir, "/path/to/log")
defaultCacheDBPath := filepath.Join(wd, "cache.db")
f.StringVar(&c.Conf.CacheDBPath, "cachedb-path", defaultCacheDBPath,
"/path/to/cache.db (local cache of changelog for Ubuntu/Debian)")
f.BoolVar(&c.Conf.SSHNative, "ssh-native-insecure", false,
"Use Native Go implementation of SSH. Default: Use the external command")
f.BoolVar(&c.Conf.SSHConfig, "ssh-config", false,
"[Deprecated] Use SSH options specified in ssh_config preferentially")
f.BoolVar(&c.Conf.ContainersOnly, "containers-only", false,
"Scan running containers only. Default: Scan both of hosts and running containers")
f.BoolVar(&c.Conf.LibsOnly, "libs-only", false,
"Scan libraries (lock files) specified in config.toml only.")
f.BoolVar(&c.Conf.WordPressOnly, "wordpress-only", false,
"Scan WordPress only.")
f.BoolVar(&c.Conf.SkipBroken, "skip-broken", false,
"[For CentOS] yum update changelog with --skip-broken option")
f.StringVar(&c.Conf.HTTPProxy, "http-proxy", "",
"http://proxy-url:port (default: empty)")
f.BoolVar(&p.askKeyPassword, "ask-key-password", false,
"Ask ssh privatekey password before scanning",
)
f.BoolVar(&c.Conf.Pipe, "pipe", false, "Use stdin via PIPE")
f.BoolVar(&c.Conf.DetectIPS, "ips", false, "retrieve IPS information")
f.BoolVar(&c.Conf.Vvv, "vvv", false, "ssh -vvv")
f.IntVar(&p.timeoutSec, "timeout", 5*60,
"Number of seconds for processing other than scan",
)
f.IntVar(&p.scanTimeoutSec, "timeout-scan", 120*60,
"Number of seconds for scanning vulnerabilities for all servers",
)
}
// Execute execute
func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
// Setup Logger
util.Log = util.NewCustomLogger(c.ServerInfo{})
if err := mkdirDotVuls(); err != nil {
util.Log.Errorf("Failed to create .vuls. err: %+v", err)
return subcommands.ExitUsageError
}
var keyPass string
var err error
if p.askKeyPassword {
prompt := "SSH key password: "
if keyPass, err = getPasswd(prompt); err != nil {
util.Log.Error(err)
return subcommands.ExitFailure
}
}
err = c.Load(p.configPath, keyPass)
if err != nil {
msg := []string{
fmt.Sprintf("Error loading %s", p.configPath),
"If you update Vuls and get this error, there may be incompatible changes in config.toml",
"Please check config.toml template : https://vuls.io/docs/en/usage-settings.html",
}
util.Log.Errorf("%s\n%+v", strings.Join(msg, "\n"), err)
return subcommands.ExitUsageError
}
if c.Conf.SSHConfig {
msg := []string{
"-ssh-config is deprecated",
"If you update Vuls and get this error, there may be incompatible changes in config.toml",
"Please check config.toml template : https://vuls.io/docs/en/usage-settings.html",
}
util.Log.Errorf("%s", strings.Join(msg, "\n"))
return subcommands.ExitUsageError
}
util.Log.Info("Start scanning")
util.Log.Infof("config: %s", p.configPath)
var servernames []string
if 0 < len(f.Args()) {
servernames = f.Args()
} else if c.Conf.Pipe {
bytes, err := ioutil.ReadAll(os.Stdin)
if err != nil {
util.Log.Errorf("Failed to read stdin. err: %+v", err)
return subcommands.ExitFailure
}
fields := strings.Fields(string(bytes))
if 0 < len(fields) {
servernames = fields
}
}
target := make(map[string]c.ServerInfo)
for _, arg := range servernames {
found := false
for servername, info := range c.Conf.Servers {
if servername == arg {
target[servername] = info
found = true
break
}
}
if !found {
util.Log.Errorf("%s is not in config", arg)
return subcommands.ExitUsageError
}
}
if 0 < len(servernames) {
c.Conf.Servers = target
}
util.Log.Debugf("%s", pp.Sprintf("%v", target))
util.Log.Info("Validating config...")
if !c.Conf.ValidateOnScan() {
return subcommands.ExitUsageError
}
util.Log.Info("Detecting Server/Container OS... ")
if err := scan.InitServers(p.timeoutSec); err != nil {
util.Log.Errorf("Failed to init servers: %+v", err)
return subcommands.ExitFailure
}
util.Log.Info("Checking Scan Modes... ")
if err := scan.CheckScanModes(); err != nil {
util.Log.Errorf("Fix config.toml. err: %+v", err)
return subcommands.ExitFailure
}
util.Log.Info("Detecting Platforms... ")
scan.DetectPlatforms(p.timeoutSec)
util.Log.Info("Detecting IPS identifiers... ")
scan.DetectIPSs(p.timeoutSec)
util.Log.Info("Scanning vulnerabilities... ")
if err := scan.Scan(p.scanTimeoutSec); err != nil {
util.Log.Errorf("Failed to scan. err: %+v", err)
return subcommands.ExitFailure
}
fmt.Printf("\n\n\n")
fmt.Println("To view the detail, vuls tui is useful.")
fmt.Println("To send a report, run vuls report -h.")
return subcommands.ExitSuccess
}

View File

@@ -1,241 +0,0 @@
package commands
import (
"context"
"flag"
"fmt"
"net/http"
"os"
"path/filepath"
// "github.com/future-architect/vuls/Server"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/exploit"
"github.com/future-architect/vuls/gost"
"github.com/future-architect/vuls/msf"
"github.com/future-architect/vuls/oval"
"github.com/future-architect/vuls/report"
"github.com/future-architect/vuls/server"
"github.com/future-architect/vuls/util"
"github.com/google/subcommands"
)
// ServerCmd is subcommand for server
type ServerCmd struct {
configPath string
listen string
cveDict c.GoCveDictConf
ovalDict c.GovalDictConf
gostConf c.GostConf
exploitConf c.ExploitConf
metasploitConf c.MetasploitConf
}
// Name return subcommand name
func (*ServerCmd) Name() string { return "server" }
// Synopsis return synopsis
func (*ServerCmd) Synopsis() string { return "Server" }
// Usage return usage
func (*ServerCmd) Usage() string {
return `Server:
Server
[-lang=en|ja]
[-config=/path/to/config.toml]
[-log-dir=/path/to/log]
[-cvss-over=7]
[-ignore-unscored-cves]
[-ignore-unfixed]
[-to-localfile]
[-format-json]
[-http-proxy=http://192.168.0.1:8080]
[-debug]
[-debug-sql]
[-listen=localhost:5515]
[-cvedb-type=sqlite3|mysql|postgres|redis|http]
[-cvedb-sqlite3-path=/path/to/cve.sqlite3]
[-cvedb-url=http://127.0.0.1:1323 or DB connection string]
[-ovaldb-type=sqlite3|mysql|redis|http]
[-ovaldb-sqlite3-path=/path/to/oval.sqlite3]
[-ovaldb-url=http://127.0.0.1:1324 or DB connection string]
[-gostdb-type=sqlite3|mysql|redis|http]
[-gostdb-sqlite3-path=/path/to/gost.sqlite3]
[-gostdb-url=http://127.0.0.1:1325 or DB connection string]
[-exploitdb-type=sqlite3|mysql|redis|http]
[-exploitdb-sqlite3-path=/path/to/exploitdb.sqlite3]
[-exploitdb-url=http://127.0.0.1:1326 or DB connection string]
[-msfdb-type=sqlite3|mysql|redis|http]
[-msfdb-sqlite3-path=/path/to/msfdb.sqlite3]
[-msfdb-url=http://127.0.0.1:1327 or DB connection string]
[RFC3339 datetime format under results dir]
`
}
// SetFlags set flag
func (p *ServerCmd) SetFlags(f *flag.FlagSet) {
f.StringVar(&c.Conf.Lang, "lang", "en", "[en|ja]")
f.BoolVar(&c.Conf.Debug, "debug", false, "debug mode")
f.BoolVar(&c.Conf.DebugSQL, "debug-sql", false, "SQL debug mode")
wd, _ := os.Getwd()
f.StringVar(&p.configPath, "config", "", "/path/to/toml")
defaultResultsDir := filepath.Join(wd, "results")
f.StringVar(&c.Conf.ResultsDir, "results-dir", defaultResultsDir, "/path/to/results")
defaultLogDir := util.GetDefaultLogDir()
f.StringVar(&c.Conf.LogDir, "log-dir", defaultLogDir, "/path/to/log")
f.Float64Var(&c.Conf.CvssScoreOver, "cvss-over", 0,
"-cvss-over=6.5 means Servering CVSS Score 6.5 and over (default: 0 (means Server all))")
f.BoolVar(&c.Conf.IgnoreUnscoredCves, "ignore-unscored-cves", false,
"Don't Server the unscored CVEs")
f.BoolVar(&c.Conf.IgnoreUnfixed, "ignore-unfixed", false,
"Don't Server the unfixed CVEs")
f.StringVar(&c.Conf.HTTPProxy, "http-proxy", "",
"http://proxy-url:port (default: empty)")
f.BoolVar(&c.Conf.FormatJSON, "format-json", false, "JSON format")
f.BoolVar(&c.Conf.ToLocalFile, "to-localfile", false, "Write report to localfile")
f.StringVar(&p.listen, "listen", "localhost:5515",
"host:port (default: localhost:5515)")
f.StringVar(&p.cveDict.Type, "cvedb-type", "",
"DB type of go-cve-dictionary (sqlite3, mysql, postgres, redis or http)")
f.StringVar(&p.cveDict.SQLite3Path, "cvedb-sqlite3-path", "", "/path/to/sqlite3")
f.StringVar(&p.cveDict.URL, "cvedb-url", "",
"http://go-cve-dictionary.com:1323 or DB connection string")
f.StringVar(&p.ovalDict.Type, "ovaldb-type", "",
"DB type of goval-dictionary (sqlite3, mysql, postgres, redis or http)")
f.StringVar(&p.ovalDict.SQLite3Path, "ovaldb-sqlite3-path", "", "/path/to/sqlite3")
f.StringVar(&p.ovalDict.URL, "ovaldb-url", "",
"http://goval-dictionary.com:1324 or DB connection string")
f.StringVar(&p.gostConf.Type, "gostdb-type", "",
"DB type of gost (sqlite3, mysql, postgres, redis or http)")
f.StringVar(&p.gostConf.SQLite3Path, "gostdb-sqlite3-path", "", "/path/to/sqlite3")
f.StringVar(&p.gostConf.URL, "gostdb-url", "",
"http://gost.com:1325 or DB connection string")
f.StringVar(&p.exploitConf.Type, "exploitdb-type", "",
"DB type of exploit (sqlite3, mysql, postgres, redis or http)")
f.StringVar(&p.exploitConf.SQLite3Path, "exploitdb-sqlite3-path", "", "/path/to/sqlite3")
f.StringVar(&p.exploitConf.URL, "exploitdb-url", "",
"http://exploit.com:1326 or DB connection string")
f.StringVar(&p.metasploitConf.Type, "msfdb-type", "",
"DB type of msf (sqlite3, mysql, postgres, redis or http)")
f.StringVar(&p.metasploitConf.SQLite3Path, "msfdb-sqlite3-path", "", "/path/to/sqlite3")
f.StringVar(&p.metasploitConf.URL, "msfdb-url", "",
"http://metasploit.com:1327 or DB connection string")
}
// Execute execute
func (p *ServerCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
util.Log = util.NewCustomLogger(c.ServerInfo{})
if p.configPath != "" {
if err := c.Load(p.configPath, ""); err != nil {
util.Log.Errorf("Error loading %s. err: %+v", p.configPath, err)
return subcommands.ExitUsageError
}
}
c.Conf.CveDict.Overwrite(p.cveDict)
c.Conf.OvalDict.Overwrite(p.ovalDict)
c.Conf.Gost.Overwrite(p.gostConf)
c.Conf.Exploit.Overwrite(p.exploitConf)
c.Conf.Metasploit.Overwrite(p.metasploitConf)
util.Log.Info("Validating config...")
if !c.Conf.ValidateOnReport() {
return subcommands.ExitUsageError
}
util.Log.Info("Validating db config...")
if !c.Conf.ValidateOnReportDB() {
return subcommands.ExitUsageError
}
if c.Conf.CveDict.URL != "" {
if err := report.CveClient.CheckHealth(); err != nil {
util.Log.Errorf("CVE HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-cve-dictionary as server mode before reporting or run with `-cvedb-type=sqlite3 -cvedb-sqlite3-path` option instead of -cvedb-url")
return subcommands.ExitFailure
}
}
if c.Conf.OvalDict.URL != "" {
err := oval.Base{}.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("OVAL HTTP server is not running. err: %s", err)
util.Log.Errorf("Run goval-dictionary as server mode before reporting or run with `-ovaldb-type=sqlite3 -ovaldb-sqlite3-path` option instead of -ovaldb-url")
return subcommands.ExitFailure
}
}
if c.Conf.Gost.URL != "" {
util.Log.Infof("gost: %s", c.Conf.Gost.URL)
err := gost.Base{}.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("gost HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run gost as server mode before reporting or run with `-gostdb-type=sqlite3 -gostdb-sqlite3-path` option instead of -gostdb-url")
return subcommands.ExitFailure
}
}
if c.Conf.Exploit.URL != "" {
err := exploit.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("exploit HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-exploitdb as server mode before reporting")
return subcommands.ExitFailure
}
}
if c.Conf.Metasploit.URL != "" {
err := msf.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("metasploit HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-msfdb as server mode before reporting")
return subcommands.ExitFailure
}
}
dbclient, locked, err := report.NewDBClient(report.DBClientConf{
CveDictCnf: c.Conf.CveDict,
OvalDictCnf: c.Conf.OvalDict,
GostCnf: c.Conf.Gost,
ExploitCnf: c.Conf.Exploit,
MetasploitCnf: c.Conf.Metasploit,
DebugSQL: c.Conf.DebugSQL,
})
if locked {
util.Log.Errorf("SQLite3 is locked. Close other DB connections and try again: %+v", err)
return subcommands.ExitFailure
}
if err != nil {
util.Log.Errorf("Failed to init DB Clients. err: %+v", err)
return subcommands.ExitFailure
}
defer dbclient.CloseDB()
http.Handle("/vuls", server.VulsHandler{DBclient: *dbclient})
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "ok")
})
util.Log.Infof("Listening on %s", p.listen)
if err := http.ListenAndServe(p.listen, nil); err != nil {
util.Log.Errorf("Failed to start server. err: %+v", err)
return subcommands.ExitFailure
}
return subcommands.ExitSuccess
}

View File

@@ -1,265 +0,0 @@
package commands
import (
"context"
"flag"
"os"
"path/filepath"
"github.com/aquasecurity/trivy/pkg/utils"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/exploit"
"github.com/future-architect/vuls/gost"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/msf"
"github.com/future-architect/vuls/oval"
"github.com/future-architect/vuls/report"
"github.com/future-architect/vuls/util"
"github.com/google/subcommands"
)
// TuiCmd is Subcommand of host discovery mode
type TuiCmd struct {
configPath string
cveDict c.GoCveDictConf
ovalDict c.GovalDictConf
gostConf c.GostConf
exploitConf c.ExploitConf
metasploitConf c.MetasploitConf
}
// Name return subcommand name
func (*TuiCmd) Name() string { return "tui" }
// Synopsis return synopsis
func (*TuiCmd) Synopsis() string { return "Run Tui view to analyze vulnerabilities" }
// Usage return usage
func (*TuiCmd) Usage() string {
return `tui:
tui
[-refresh-cve]
[-config=/path/to/config.toml]
[-cvss-over=7]
[-diff]
[-ignore-unscored-cves]
[-ignore-unfixed]
[-results-dir=/path/to/results]
[-log-dir=/path/to/log]
[-debug]
[-debug-sql]
[-quiet]
[-no-progress]
[-pipe]
[-cvedb-type=sqlite3|mysql|postgres|redis|http]
[-cvedb-sqlite3-path=/path/to/cve.sqlite3]
[-cvedb-url=http://127.0.0.1:1323 or DB connection string]
[-ovaldb-type=sqlite3|mysql|redis|http]
[-ovaldb-sqlite3-path=/path/to/oval.sqlite3]
[-ovaldb-url=http://127.0.0.1:1324 or DB connection string]
[-gostdb-type=sqlite3|mysql|redis|http]
[-gostdb-sqlite3-path=/path/to/gost.sqlite3]
[-gostdb-url=http://127.0.0.1:1325 or DB connection string]
[-exploitdb-type=sqlite3|mysql|redis|http]
[-exploitdb-sqlite3-path=/path/to/exploitdb.sqlite3]
[-exploitdb-url=http://127.0.0.1:1326 or DB connection string]
[-msfdb-type=sqlite3|mysql|redis|http]
[-msfdb-sqlite3-path=/path/to/msfdb.sqlite3]
[-msfdb-url=http://127.0.0.1:1327 or DB connection string]
[-trivy-cachedb-dir=/path/to/dir]
`
}
// SetFlags set flag
func (p *TuiCmd) SetFlags(f *flag.FlagSet) {
// f.StringVar(&p.lang, "lang", "en", "[en|ja]")
f.BoolVar(&c.Conf.DebugSQL, "debug-sql", false, "debug SQL")
f.BoolVar(&c.Conf.Debug, "debug", false, "debug mode")
f.BoolVar(&c.Conf.Quiet, "quiet", false, "Quiet mode. No output on stdout")
f.BoolVar(&c.Conf.NoProgress, "no-progress", false, "Suppress progress bar")
defaultLogDir := util.GetDefaultLogDir()
f.StringVar(&c.Conf.LogDir, "log-dir", defaultLogDir, "/path/to/log")
wd, _ := os.Getwd()
defaultResultsDir := filepath.Join(wd, "results")
f.StringVar(&c.Conf.ResultsDir, "results-dir", defaultResultsDir, "/path/to/results")
defaultConfPath := filepath.Join(wd, "config.toml")
f.StringVar(&p.configPath, "config", defaultConfPath, "/path/to/toml")
f.BoolVar(&c.Conf.RefreshCve, "refresh-cve", false,
"Refresh CVE information in JSON file under results dir")
f.Float64Var(&c.Conf.CvssScoreOver, "cvss-over", 0,
"-cvss-over=6.5 means reporting CVSS Score 6.5 and over (default: 0 (means report all))")
f.BoolVar(&c.Conf.Diff, "diff", false,
"Difference between previous result and current result ")
f.BoolVar(
&c.Conf.IgnoreUnscoredCves, "ignore-unscored-cves", false,
"Don't report the unscored CVEs")
f.BoolVar(&c.Conf.IgnoreUnfixed, "ignore-unfixed", false,
"Don't report the unfixed CVEs")
f.BoolVar(&c.Conf.Pipe, "pipe", false, "Use stdin via PIPE")
f.StringVar(&p.cveDict.Type, "cvedb-type", "",
"DB type of go-cve-dictionary (sqlite3, mysql, postgres or redis)")
f.StringVar(&p.cveDict.SQLite3Path, "cvedb-path", "", "/path/to/sqlite3")
f.StringVar(&p.cveDict.URL, "cvedb-url", "",
"http://go-cve-dictionary.com:1323 or DB connection string")
f.StringVar(&p.ovalDict.Type, "ovaldb-type", "",
"DB type of goval-dictionary (sqlite3, mysql, postgres or redis)")
f.StringVar(&p.ovalDict.SQLite3Path, "ovaldb-path", "", "/path/to/sqlite3")
f.StringVar(&p.ovalDict.URL, "ovaldb-url", "",
"http://goval-dictionary.com:1324 or DB connection string")
f.StringVar(&p.gostConf.Type, "gostdb-type", "",
"DB type of gost (sqlite3, mysql, postgres or redis)")
f.StringVar(&p.gostConf.SQLite3Path, "gostdb-path", "", "/path/to/sqlite3")
f.StringVar(&p.gostConf.URL, "gostdb-url", "",
"http://gost.com:1325 or DB connection string")
f.StringVar(&p.exploitConf.Type, "exploitdb-type", "",
"DB type of exploit (sqlite3, mysql, postgres, redis or http)")
f.StringVar(&p.exploitConf.SQLite3Path, "exploitdb-sqlite3-path", "", "/path/to/sqlite3")
f.StringVar(&p.exploitConf.URL, "exploitdb-url", "",
"http://exploit.com:1326 or DB connection string")
f.StringVar(&p.metasploitConf.Type, "msfdb-type", "",
"DB type of msf (sqlite3, mysql, postgres, redis or http)")
f.StringVar(&p.metasploitConf.SQLite3Path, "msfdb-sqlite3-path", "", "/path/to/sqlite3")
f.StringVar(&p.metasploitConf.URL, "msfdb-url", "",
"http://metasploit.com:1327 or DB connection string")
f.StringVar(&c.Conf.TrivyCacheDBDir, "trivy-cachedb-dir",
utils.DefaultCacheDir(), "/path/to/dir")
}
// Execute execute
func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
util.Log = util.NewCustomLogger(c.ServerInfo{})
if err := c.Load(p.configPath, ""); err != nil {
util.Log.Errorf("Error loading %s, err: %+v", p.configPath, err)
return subcommands.ExitUsageError
}
c.Conf.Lang = "en"
c.Conf.CveDict.Overwrite(p.cveDict)
c.Conf.OvalDict.Overwrite(p.ovalDict)
c.Conf.Gost.Overwrite(p.gostConf)
c.Conf.Exploit.Overwrite(p.exploitConf)
c.Conf.Metasploit.Overwrite(p.metasploitConf)
var dir string
var err error
if c.Conf.Diff {
dir, err = report.JSONDir([]string{})
} else {
dir, err = report.JSONDir(f.Args())
}
if err != nil {
util.Log.Errorf("Failed to read from JSON. err: %+v", err)
return subcommands.ExitFailure
}
util.Log.Info("Validating config...")
if !c.Conf.ValidateOnTui() {
return subcommands.ExitUsageError
}
var res models.ScanResults
if res, err = report.LoadScanResults(dir); err != nil {
util.Log.Error(err)
return subcommands.ExitFailure
}
util.Log.Infof("Loaded: %s", dir)
util.Log.Info("Validating db config...")
if !c.Conf.ValidateOnReportDB() {
return subcommands.ExitUsageError
}
if c.Conf.CveDict.URL != "" {
if err := report.CveClient.CheckHealth(); err != nil {
util.Log.Errorf("CVE HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-cve-dictionary as server mode before reporting or run with `-cvedb-type=sqlite3 -cvedb-sqlite3-path` option instead of -cvedb-url")
return subcommands.ExitFailure
}
}
if c.Conf.OvalDict.URL != "" {
err := oval.Base{}.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("OVAL HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run goval-dictionary as server mode before reporting or run with `-ovaldb-type=sqlite3 -ovaldb-sqlite3-path` option instead of -ovaldb-url")
return subcommands.ExitFailure
}
}
if c.Conf.Gost.URL != "" {
util.Log.Infof("gost: %s", c.Conf.Gost.URL)
err := gost.Base{}.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("gost HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run gost as server mode before reporting or run with `-gostdb-type=sqlite3 -gostdb-sqlite3-path` option instead of -gostdb-url")
return subcommands.ExitFailure
}
}
if c.Conf.Exploit.URL != "" {
err := exploit.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("exploit HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-exploitdb as server mode before reporting")
return subcommands.ExitFailure
}
}
if c.Conf.Metasploit.URL != "" {
err := msf.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("metasploit HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-msfdb as server mode before reporting")
return subcommands.ExitFailure
}
}
dbclient, locked, err := report.NewDBClient(report.DBClientConf{
CveDictCnf: c.Conf.CveDict,
OvalDictCnf: c.Conf.OvalDict,
GostCnf: c.Conf.Gost,
ExploitCnf: c.Conf.Exploit,
MetasploitCnf: c.Conf.Metasploit,
DebugSQL: c.Conf.DebugSQL,
})
if locked {
util.Log.Errorf("SQLite3 is locked. Close other DB connections and try again: %+v", err)
return subcommands.ExitFailure
}
if err != nil {
util.Log.Errorf("Failed to init DB Clients. err: %+v", err)
return subcommands.ExitFailure
}
defer dbclient.CloseDB()
if res, err = report.FillCveInfos(*dbclient, res, dir); err != nil {
util.Log.Error(err)
return subcommands.ExitFailure
}
for _, r := range res {
if len(r.Warnings) != 0 {
util.Log.Warnf("Warning: Some warnings occurred while scanning on %s: %s",
r.FormatServerName(), r.Warnings)
}
}
return report.RunTui(res)
}

View File

@@ -1,39 +0,0 @@
package commands
import (
"fmt"
"os"
"path/filepath"
"github.com/howeyc/gopass"
homedir "github.com/mitchellh/go-homedir"
"golang.org/x/xerrors"
)
func getPasswd(prompt string) (string, error) {
for {
fmt.Print(prompt)
pass, err := gopass.GetPasswdMasked()
if err != nil {
return "", xerrors.New("Failed to read a password")
}
if 0 < len(pass) {
return string(pass), nil
}
}
}
func mkdirDotVuls() error {
home, err := homedir.Dir()
if err != nil {
return err
}
dotVuls := filepath.Join(home, ".vuls")
if _, err := os.Stat(dotVuls); os.IsNotExist(err) {
if err := os.Mkdir(dotVuls, 0700); err != nil {
return err
}
}
return nil
}

View File

@@ -1,15 +0,0 @@
package config
var (
// Colors has ansi color list
Colors = []string{
"\033[32m", // green
"\033[33m", // yellow
"\033[36m", // cyan
"\033[35m", // magenta
"\033[31m", // red
"\033[34m", // blue
}
// ResetColor is reset color
ResetColor = "\033[0m"
)

File diff suppressed because it is too large Load Diff

View File

@@ -1,103 +0,0 @@
package config
import (
"testing"
)
func TestSyslogConfValidate(t *testing.T) {
var tests = []struct {
conf SyslogConf
expectedErrLength int
}{
{
conf: SyslogConf{},
expectedErrLength: 0,
},
{
conf: SyslogConf{
Protocol: "tcp",
Port: "5140",
},
expectedErrLength: 0,
},
{
conf: SyslogConf{
Protocol: "udp",
Port: "12345",
Severity: "emerg",
Facility: "user",
},
expectedErrLength: 0,
},
{
conf: SyslogConf{
Protocol: "foo",
Port: "514",
},
expectedErrLength: 1,
},
{
conf: SyslogConf{
Protocol: "invalid",
Port: "-1",
},
expectedErrLength: 2,
},
{
conf: SyslogConf{
Protocol: "invalid",
Port: "invalid",
Severity: "invalid",
Facility: "invalid",
},
expectedErrLength: 4,
},
}
for i, tt := range tests {
Conf.ToSyslog = true
errs := tt.conf.Validate()
if len(errs) != tt.expectedErrLength {
t.Errorf("test: %d, expected %d, actual %d", i, tt.expectedErrLength, len(errs))
}
}
}
func TestDistro_MajorVersion(t *testing.T) {
var tests = []struct {
in Distro
out int
}{
{
in: Distro{
Family: Amazon,
Release: "2 (2017.12)",
},
out: 2,
},
{
in: Distro{
Family: Amazon,
Release: "2017.12",
},
out: 1,
},
{
in: Distro{
Family: CentOS,
Release: "7.10",
},
out: 7,
},
}
for i, tt := range tests {
ver, err := tt.in.MajorVersion()
if err != nil {
t.Errorf("[%d] err occurred: %s", i, err)
}
if tt.out != ver {
t.Errorf("[%d] expected %d, actual %d", i, tt.out, ver)
}
}
}

View File

@@ -1,9 +0,0 @@
package config
// IPS is
type IPS string
const (
// DeepSecurity is
DeepSecurity IPS = "deepsecurity"
)

View File

@@ -1,12 +0,0 @@
package config
import "golang.org/x/xerrors"
// JSONLoader loads configuration
type JSONLoader struct {
}
// Load load the configuration JSON file specified by path arg.
func (c JSONLoader) Load(path, sudoPass, keyPass string) (err error) {
return xerrors.New("Not implement yet")
}

View File

@@ -1,13 +0,0 @@
package config
// Load loads configuration
func Load(path, keyPass string) error {
var loader Loader
loader = TOMLLoader{}
return loader.Load(path, keyPass)
}
// Loader is interface of concrete loader
type Loader interface {
Load(string, string) error
}

View File

@@ -1,295 +0,0 @@
package config
import (
"regexp"
"strings"
"github.com/BurntSushi/toml"
"github.com/knqyf263/go-cpe/naming"
"golang.org/x/xerrors"
)
// TOMLLoader loads config
type TOMLLoader struct {
}
// Load load the configuration TOML file specified by path arg.
func (c TOMLLoader) Load(pathToToml, keyPass string) error {
var conf Config
if _, err := toml.DecodeFile(pathToToml, &conf); err != nil {
return err
}
Conf.EMail = conf.EMail
Conf.Slack = conf.Slack
Conf.Stride = conf.Stride
Conf.HipChat = conf.HipChat
Conf.ChatWork = conf.ChatWork
Conf.Telegram = conf.Telegram
Conf.Saas = conf.Saas
Conf.Syslog = conf.Syslog
Conf.HTTP = conf.HTTP
Conf.AWS = conf.AWS
Conf.Azure = conf.Azure
Conf.CveDict = conf.CveDict
Conf.OvalDict = conf.OvalDict
Conf.Gost = conf.Gost
Conf.Exploit = conf.Exploit
Conf.Metasploit = conf.Metasploit
d := conf.Default
Conf.Default = d
servers := make(map[string]ServerInfo)
if keyPass != "" {
d.KeyPassword = keyPass
}
i := 0
for serverName, v := range conf.Servers {
if 0 < len(v.KeyPassword) {
return xerrors.Errorf("[Deprecated] KEYPASSWORD IN CONFIG FILE ARE UNSECURE. REMOVE THEM IMMEDIATELY FOR A SECURITY REASONS. THEY WILL BE REMOVED IN A FUTURE RELEASE: %s", serverName)
}
s := ServerInfo{ServerName: serverName}
if v.Type != ServerTypePseudo {
s.Host = v.Host
if len(s.Host) == 0 {
return xerrors.Errorf("%s is invalid. host is empty", serverName)
}
s.JumpServer = v.JumpServer
if len(s.JumpServer) == 0 {
s.JumpServer = d.JumpServer
}
switch {
case v.Port != "":
s.Port = v.Port
case d.Port != "":
s.Port = d.Port
default:
s.Port = "22"
}
switch {
case v.User != "":
s.User = v.User
case d.User != "":
s.User = d.User
default:
if s.Port != "local" {
return xerrors.Errorf("%s is invalid. User is empty", serverName)
}
}
s.SSHConfigPath = v.SSHConfigPath
if len(s.SSHConfigPath) == 0 {
s.SSHConfigPath = d.SSHConfigPath
}
s.KeyPath = v.KeyPath
if len(s.KeyPath) == 0 {
s.KeyPath = d.KeyPath
}
s.KeyPassword = v.KeyPassword
if len(s.KeyPassword) == 0 {
s.KeyPassword = d.KeyPassword
}
}
s.ScanMode = v.ScanMode
if len(s.ScanMode) == 0 {
s.ScanMode = d.ScanMode
if len(s.ScanMode) == 0 {
s.ScanMode = []string{"fast"}
}
}
for _, m := range s.ScanMode {
switch m {
case "fast":
s.Mode.Set(Fast)
case "fast-root":
s.Mode.Set(FastRoot)
case "deep":
s.Mode.Set(Deep)
case "offline":
s.Mode.Set(Offline)
default:
return xerrors.Errorf("scanMode: %s of %s is invalid. Specify -fast, -fast-root, -deep or offline", m, serverName)
}
}
if err := s.Mode.validate(); err != nil {
return xerrors.Errorf("%s in %s", err, serverName)
}
s.CpeNames = v.CpeNames
if len(s.CpeNames) == 0 {
s.CpeNames = d.CpeNames
}
s.Lockfiles = v.Lockfiles
if len(s.Lockfiles) == 0 {
s.Lockfiles = d.Lockfiles
}
s.FindLock = v.FindLock
for i, n := range s.CpeNames {
uri, err := toCpeURI(n)
if err != nil {
return xerrors.Errorf("Failed to parse CPENames %s in %s, err: %w", n, serverName, err)
}
s.CpeNames[i] = uri
}
s.ContainersIncluded = v.ContainersIncluded
if len(s.ContainersIncluded) == 0 {
s.ContainersIncluded = d.ContainersIncluded
}
s.ContainersExcluded = v.ContainersExcluded
if len(s.ContainersExcluded) == 0 {
s.ContainersExcluded = d.ContainersExcluded
}
s.ContainerType = v.ContainerType
if len(s.ContainerType) == 0 {
s.ContainerType = d.ContainerType
}
s.Containers = v.Containers
for contName, cont := range s.Containers {
cont.IgnoreCves = append(cont.IgnoreCves, d.IgnoreCves...)
s.Containers[contName] = cont
}
if len(v.DependencyCheckXMLPath) != 0 || len(d.DependencyCheckXMLPath) != 0 {
return xerrors.Errorf("[DEPRECATED] dependencyCheckXMLPath IS DEPRECATED. USE owaspDCXMLPath INSTEAD: %s", serverName)
}
s.OwaspDCXMLPath = v.OwaspDCXMLPath
if len(s.OwaspDCXMLPath) == 0 {
s.OwaspDCXMLPath = d.OwaspDCXMLPath
}
s.Memo = v.Memo
if s.Memo == "" {
s.Memo = d.Memo
}
s.IgnoreCves = v.IgnoreCves
for _, cve := range d.IgnoreCves {
found := false
for _, c := range s.IgnoreCves {
if cve == c {
found = true
break
}
}
if !found {
s.IgnoreCves = append(s.IgnoreCves, cve)
}
}
s.IgnorePkgsRegexp = v.IgnorePkgsRegexp
for _, pkg := range d.IgnorePkgsRegexp {
found := false
for _, p := range s.IgnorePkgsRegexp {
if pkg == p {
found = true
break
}
}
if !found {
s.IgnorePkgsRegexp = append(s.IgnorePkgsRegexp, pkg)
}
}
for _, reg := range s.IgnorePkgsRegexp {
_, err := regexp.Compile(reg)
if err != nil {
return xerrors.Errorf("Failed to parse %s in %s. err: %w", reg, serverName, err)
}
}
for contName, cont := range s.Containers {
for _, reg := range cont.IgnorePkgsRegexp {
_, err := regexp.Compile(reg)
if err != nil {
return xerrors.Errorf("Failed to parse %s in %s@%s. err: %w",
reg, contName, serverName, err)
}
}
}
opt := map[string]interface{}{}
for k, v := range d.Optional {
opt[k] = v
}
for k, v := range v.Optional {
opt[k] = v
}
s.Optional = opt
s.Enablerepo = v.Enablerepo
if len(s.Enablerepo) == 0 {
s.Enablerepo = d.Enablerepo
}
if len(s.Enablerepo) != 0 {
for _, repo := range s.Enablerepo {
switch repo {
case "base", "updates":
// nop
default:
return xerrors.Errorf(
"For now, enablerepo have to be base or updates: %s, servername: %s",
s.Enablerepo, serverName)
}
}
}
s.GitHubRepos = v.GitHubRepos
for ownerRepo, githubSetting := range s.GitHubRepos {
if ss := strings.Split(ownerRepo, "/"); len(ss) != 2 {
return xerrors.Errorf("Failed to parse GitHub owner/repo: %s in %s",
ownerRepo, serverName)
}
if githubSetting.Token == "" {
return xerrors.Errorf("GitHub owner/repo: %s in %s token is empty",
ownerRepo, serverName)
}
}
s.UUIDs = v.UUIDs
s.Type = v.Type
s.WordPress.WPVulnDBToken = v.WordPress.WPVulnDBToken
s.WordPress.CmdPath = v.WordPress.CmdPath
s.WordPress.DocRoot = v.WordPress.DocRoot
s.WordPress.OSUser = v.WordPress.OSUser
s.WordPress.IgnoreInactive = v.WordPress.IgnoreInactive
s.LogMsgAnsiColor = Colors[i%len(Colors)]
i++
servers[serverName] = s
}
Conf.Servers = servers
return nil
}
func toCpeURI(cpename string) (string, error) {
if strings.HasPrefix(cpename, "cpe:2.3:") {
wfn, err := naming.UnbindFS(cpename)
if err != nil {
return "", err
}
return naming.BindToURI(wfn), nil
} else if strings.HasPrefix(cpename, "cpe:/") {
wfn, err := naming.UnbindURI(cpename)
if err != nil {
return "", err
}
return naming.BindToURI(wfn), nil
}
return "", xerrors.Errorf("Unknown CPE format: %s", cpename)
}

View File

@@ -1,44 +0,0 @@
package config
import (
"testing"
)
func TestToCpeURI(t *testing.T) {
var tests = []struct {
in string
expected string
err bool
}{
{
in: "",
expected: "",
err: true,
},
{
in: "cpe:/a:microsoft:internet_explorer:10",
expected: "cpe:/a:microsoft:internet_explorer:10",
err: false,
},
{
in: "cpe:2.3:a:microsoft:internet_explorer:10:*:*:*:*:*:*:*",
expected: "cpe:/a:microsoft:internet_explorer:10",
err: false,
},
}
for i, tt := range tests {
actual, err := toCpeURI(tt.in)
if err != nil && !tt.err {
t.Errorf("[%d] unexpected error occurred, in: %s act: %s, exp: %s",
i, tt.in, actual, tt.expected)
} else if err == nil && tt.err {
t.Errorf("[%d] expected error is not occurred, in: %s act: %s, exp: %s",
i, tt.in, actual, tt.expected)
}
if actual != tt.expected {
t.Errorf("[%d] in: %s, actual: %s, expected: %s",
i, tt.in, actual, tt.expected)
}
}
}

View File

@@ -1,38 +0,0 @@
# future-vuls
## Main Features
- upload vuls results json to future-vuls
## Installation
```
git clone https://github.com/future-architect/vuls.git
make build-future-vuls
```
## Command Reference
```
Upload to FutureVuls
Usage:
future-vuls upload [flags]
Flags:
--config string config file (default is $HOME/.cobra.yaml)
-g, --group-id int future vuls group id, ENV: VULS_GROUP_ID
-h, --help help for upload
-s, --stdin input from stdin. ENV: VULS_STDIN
-t, --token string future vuls token
--url string future vuls upload url
--uuid string server uuid. ENV: VULS_SERVER_UUID
```
## Usage
- update results json
```
cat results.json | future-vuls upload --stdin --token xxxx --url https://xxxx --group-id 1 --uuid xxxx
```

View File

@@ -1,98 +0,0 @@
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"os"
"strconv"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/report"
"github.com/spf13/cobra"
)
var (
configFile string
stdIn bool
jsonDir string
serverUUID string
groupID int64
token string
url string
)
func main() {
var err error
var cmdFvulsUploader = &cobra.Command{
Use: "upload",
Short: "Upload to FutureVuls",
Long: `Upload to FutureVuls`,
Run: func(cmd *cobra.Command, args []string) {
if len(serverUUID) == 0 {
serverUUID = os.Getenv("VULS_SERVER_UUID")
}
if groupID == 0 {
envGroupID := os.Getenv("VULS_GROUP_ID")
if groupID, err = strconv.ParseInt(envGroupID, 10, 64); err != nil {
fmt.Printf("Invalid GroupID: %s\n", envGroupID)
return
}
}
if len(url) == 0 {
url = os.Getenv("VULS_URL")
}
if len(token) == 0 {
token = os.Getenv("VULS_TOKEN")
}
var scanResultJSON []byte
if stdIn {
reader := bufio.NewReader(os.Stdin)
buf := new(bytes.Buffer)
if _, err = buf.ReadFrom(reader); err != nil {
return
}
scanResultJSON = buf.Bytes()
} else {
fmt.Println("use --stdin option")
os.Exit(1)
return
}
var scanResult models.ScanResult
if err = json.Unmarshal(scanResultJSON, &scanResult); err != nil {
fmt.Println("Failed to parse json", err)
os.Exit(1)
return
}
scanResult.ServerUUID = serverUUID
config.Conf.Saas.GroupID = groupID
config.Conf.Saas.Token = token
config.Conf.Saas.URL = url
if err = (report.SaasWriter{}).Write(scanResult); err != nil {
fmt.Println(err)
os.Exit(1)
return
}
return
},
}
cmdFvulsUploader.PersistentFlags().StringVar(&serverUUID, "uuid", "", "server uuid. ENV: VULS_SERVER_UUID")
cmdFvulsUploader.PersistentFlags().StringVar(&configFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
cmdFvulsUploader.PersistentFlags().BoolVarP(&stdIn, "stdin", "s", false, "input from stdin. ENV: VULS_STDIN")
// TODO Read JSON file from directory
// cmdFvulsUploader.Flags().StringVarP(&jsonDir, "results-dir", "d", "./", "vuls scan results json dir")
cmdFvulsUploader.PersistentFlags().Int64VarP(&groupID, "group-id", "g", 0, "future vuls group id, ENV: VULS_GROUP_ID")
cmdFvulsUploader.PersistentFlags().StringVarP(&token, "token", "t", "", "future vuls token")
cmdFvulsUploader.PersistentFlags().StringVar(&url, "url", "", "future vuls upload url")
var rootCmd = &cobra.Command{Use: "future-vuls"}
rootCmd.AddCommand(cmdFvulsUploader)
if err = rootCmd.Execute(); err != nil {
fmt.Println("Failed to execute command", err)
}
}

View File

@@ -1,71 +0,0 @@
package parser
import (
"encoding/xml"
"io/ioutil"
"os"
"strings"
"github.com/knqyf263/go-cpe/naming"
log "github.com/sirupsen/logrus"
"golang.org/x/xerrors"
)
type analysis struct {
Dependencies []dependency `xml:"dependencies>dependency"`
}
type dependency struct {
Identifiers []vulnerabilityID `xml:"identifiers>vulnerabilityIds"`
}
type vulnerabilityID struct {
ID string `xml:"id"`
}
func appendIfMissing(slice []string, str string) []string {
for _, s := range slice {
if s == str {
return slice
}
}
return append(slice, str)
}
// Parse parses OWASP dependency check XML and collect list of cpe
func Parse(path string) ([]string, error) {
file, err := os.Open(path)
if err != nil {
log.Warnf("OWASP Dependency Check XML is not found: %s", path)
return []string{}, nil
}
defer file.Close()
b, err := ioutil.ReadAll(file)
if err != nil {
log.Warnf("Failed to read OWASP Dependency Check XML: %s", path)
return []string{}, nil
}
var anal analysis
if err := xml.Unmarshal(b, &anal); err != nil {
return nil, xerrors.Errorf("Failed to unmarshal: %s", err)
}
cpes := []string{}
for _, d := range anal.Dependencies {
for _, ident := range d.Identifiers {
id := ident.ID // Start with cpe:2.3:
// Convert from CPE 2.3 to CPE 2.2
if strings.HasPrefix(id, "cpe:2.3:") {
wfn, err := naming.UnbindFS(id)
if err != nil {
return []string{}, err
}
id = naming.BindToURI(wfn)
}
cpes = appendIfMissing(cpes, id)
}
}
return cpes, nil
}

View File

@@ -1,35 +0,0 @@
# trivy-to-vuls
## Main Features
- convert trivy's results json to vuls's report json
## Installation
```
git clone https://github.com/future-architect/vuls.git
make build-trivy-to-vuls
```
## Command Reference
```
Parse trivy json to vuls results
Usage:
trivy-to-vuls parse [flags]
Flags:
-h, --help help for parse
-s, --stdin input from stdin
-d, --trivy-json-dir string trivy json dir (default "./")
-f, --trivy-json-file-name string trivy json file name (default "results.json")
```
## Usage
- use trivy output
```
trivy -q image -f=json python:3.4-alpine | trivy-to-vuls parse --stdin
```

View File

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

View File

@@ -1,164 +0,0 @@
package parser
import (
"encoding/json"
"sort"
"time"
"github.com/aquasecurity/fanal/analyzer/os"
"github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/future-architect/vuls/models"
)
// Parse :
func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanResult, err error) {
var trivyResults report.Results
if err = json.Unmarshal(vulnJSON, &trivyResults); err != nil {
return nil, err
}
pkgs := models.Packages{}
vulnInfos := models.VulnInfos{}
uniqueLibraryScannerPaths := map[string]models.LibraryScanner{}
for _, trivyResult := range trivyResults {
for _, vuln := range trivyResult.Vulnerabilities {
if _, ok := vulnInfos[vuln.VulnerabilityID]; !ok {
vulnInfos[vuln.VulnerabilityID] = models.VulnInfo{
CveID: vuln.VulnerabilityID,
Confidences: models.Confidences{
{
Score: 100,
DetectionMethod: models.TrivyMatchStr,
},
},
AffectedPackages: models.PackageFixStatuses{},
CveContents: models.CveContents{},
LibraryFixedIns: models.LibraryFixedIns{},
// VulnType : "",
}
}
vulnInfo := vulnInfos[vuln.VulnerabilityID]
var notFixedYet bool
fixState := ""
if len(vuln.FixedVersion) == 0 {
notFixedYet = true
fixState = "Affected"
}
var references models.References
for _, reference := range vuln.References {
references = append(references, models.Reference{
Source: "trivy",
Link: reference,
})
}
sort.Slice(references, func(i, j int) bool {
return references[i].Link < references[j].Link
})
vulnInfo.CveContents = models.CveContents{
models.Trivy: models.CveContent{
Cvss3Severity: vuln.Severity,
References: references,
Title: vuln.Title,
Summary: vuln.Description,
},
}
// do only if image type is Vuln
if IsTrivySupportedOS(trivyResult.Type) {
pkgs[vuln.PkgName] = models.Package{
Name: vuln.PkgName,
Version: vuln.InstalledVersion,
}
vulnInfo.AffectedPackages = append(vulnInfo.AffectedPackages, models.PackageFixStatus{
Name: vuln.PkgName,
NotFixedYet: notFixedYet,
FixState: fixState,
FixedIn: vuln.FixedVersion,
})
// overwrite every time if os package
scanResult.Family = trivyResult.Type
scanResult.ServerName = trivyResult.Target
scanResult.Optional = map[string]interface{}{
"trivy-target": trivyResult.Target,
}
scanResult.ScannedAt = time.Now()
scanResult.ScannedBy = "trivy"
scanResult.ScannedVia = "trivy"
} else {
// LibraryScanの結果
vulnInfo.LibraryFixedIns = append(vulnInfo.LibraryFixedIns, models.LibraryFixedIn{
Key: trivyResult.Type,
Name: vuln.PkgName,
Path: trivyResult.Target,
FixedIn: vuln.FixedVersion,
})
libScanner := uniqueLibraryScannerPaths[trivyResult.Target]
libScanner.Libs = append(libScanner.Libs, types.Library{
Name: vuln.PkgName,
Version: vuln.InstalledVersion,
})
uniqueLibraryScannerPaths[trivyResult.Target] = libScanner
}
vulnInfos[vuln.VulnerabilityID] = vulnInfo
}
}
// flatten and unique libraries
libraryScanners := make([]models.LibraryScanner, 0, len(uniqueLibraryScannerPaths))
for path, v := range uniqueLibraryScannerPaths {
uniqueLibrary := map[string]types.Library{}
for _, lib := range v.Libs {
uniqueLibrary[lib.Name+lib.Version] = lib
}
var libraries []types.Library
for _, library := range uniqueLibrary {
libraries = append(libraries, library)
}
sort.Slice(libraries, func(i, j int) bool {
return libraries[i].Name < libraries[j].Name
})
libscanner := models.LibraryScanner{
Path: path,
Libs: libraries,
}
libraryScanners = append(libraryScanners, libscanner)
}
sort.Slice(libraryScanners, func(i, j int) bool {
return libraryScanners[i].Path < libraryScanners[j].Path
})
scanResult.ScannedCves = vulnInfos
scanResult.Packages = pkgs
scanResult.LibraryScanners = libraryScanners
return scanResult, nil
}
// IsTrivySupportedOS :
func IsTrivySupportedOS(family string) bool {
supportedFamilies := []string{
os.RedHat,
os.Debian,
os.Ubuntu,
os.CentOS,
os.Fedora,
os.Amazon,
os.Oracle,
os.Windows,
os.OpenSUSE,
os.OpenSUSELeap,
os.OpenSUSETumbleweed,
os.SLES,
os.Photon,
os.Alpine,
}
for _, supportedFamily := range supportedFamilies {
if family == supportedFamily {
return true
}
}
return false
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,33 +0,0 @@
package cwe
// CweTopTwentyfive2019 has CWE-ID in CWE Top 25
var CweTopTwentyfive2019 = map[string]string{
"119": "1",
"79": "2",
"20": "3",
"200": "4",
"125": "5",
"89": "6",
"416": "7",
"190": "8",
"352": "9",
"22": "10",
"78": "11",
"787": "12",
"287": "13",
"476": "14",
"732": "16",
"434": "16",
"611": "17",
"94": "18",
"798": "19",
"400": "20",
"772": "21",
"426": "22",
"502": "23",
"269": "24",
"295": "25",
}
// CweTopTwentyfive2019URL has CWE Top25 links
var CweTopTwentyfive2019URL = "https://cwe.mitre.org/top25/archive/2019/2019_cwe_top25.html"

5145
cwe/en.go

File diff suppressed because it is too large Load Diff

1027
cwe/ja.go

File diff suppressed because it is too large Load Diff

View File

@@ -1,65 +0,0 @@
package cwe
// OwaspTopTen2017 has CWE-ID in OWSP Top 10
var OwaspTopTen2017 = map[string]string{
"77": "1",
"89": "1",
"564": "1",
"917": "1",
"287": "2",
"384": "2",
"220": "3",
"310": "3",
"312": "3",
"319": "3",
"326": "3",
"359": "3",
"611": "4",
"22": "5",
"284": "5",
"285": "5",
"639": "5",
"2": "6",
"16": "6",
"388": "6",
"79": "7",
"502": "8",
"223": "10",
"778": "10",
}
// OwaspTopTen2017GitHubURLEn has GitHub links
var OwaspTopTen2017GitHubURLEn = map[string]string{
"1": "https://github.com/OWASP/Top10/blob/master/2017/en/0xa1-injection.md",
"2": "https://github.com/OWASP/Top10/blob/master/2017/en/0xa2-broken-authentication.md",
"3": "https://github.com/OWASP/Top10/blob/master/2017/en/0xa3-sensitive-data-disclosure.md",
"4": "https://github.com/OWASP/Top10/blob/master/2017/en/0xa4-xxe.md",
"5": "https://github.com/OWASP/Top10/blob/master/2017/en/0xa5-broken-access-control.md",
"6": "https://github.com/OWASP/Top10/blob/master/2017/en/0xa6-security-misconfiguration.md",
"7": "https://github.com/OWASP/Top10/blob/master/2017/en/0xa7-xss.md",
"8": "https://github.com/OWASP/Top10/blob/master/2017/en/0xa8-insecure-deserialization.md",
"9": "https://github.com/OWASP/Top10/blob/master/2017/en/0xa9-known-vulns.md<Paste>",
"10": "https://github.com/OWASP/Top10/blob/master/2017/en/0xaa-logging-detection-response.md",
}
// OwaspTopTen2017GitHubURLJa has GitHub links
var OwaspTopTen2017GitHubURLJa = map[string]string{
"1": "https://github.com/OWASP/Top10/blob/master/2017/ja/0xa1-injection.md",
"2": "https://github.com/OWASP/Top10/blob/master/2017/ja/0xa2-broken-authentication.md",
"3": "https://github.com/OWASP/Top10/blob/master/2017/ja/0xa3-sensitive-data-disclosure.md",
"4": "https://github.com/OWASP/Top10/blob/master/2017/ja/0xa4-xxe.md",
"5": "https://github.com/OWASP/Top10/blob/master/2017/ja/0xa5-broken-access-control.md",
"6": "https://github.com/OWASP/Top10/blob/master/2017/ja/0xa6-security-misconfiguration.md",
"7": "https://github.com/OWASP/Top10/blob/master/2017/ja/0xa7-xss.md",
"8": "https://github.com/OWASP/Top10/blob/master/2017/ja/0xa8-insecure-deserialization.md",
"9": "https://github.com/OWASP/Top10/blob/master/2017/ja/0xa9-known-vulns.md<Paste>",
"10": "https://github.com/OWASP/Top10/blob/master/2017/ja/0xaa-logging-detection-response.md",
}

View File

@@ -1,33 +0,0 @@
package cwe
// SansTopTwentyfive has CWE-ID in CWE/SANS Top 25
var SansTopTwentyfive = map[string]string{
"89": "1",
"78": "2",
"120": "3",
"79": "4",
"306": "5",
"862": "6",
"798": "7",
"311": "8",
"434": "9",
"807": "10",
"250": "11",
"352": "12",
"22": "13",
"494": "14",
"863": "15",
"829": "16",
"732": "17",
"676": "18",
"327": "19",
"131": "20",
"307": "21",
"601": "22",
"134": "23",
"190": "24",
"759": "25",
}
// SansTopTwentyfiveURL is a URL of sans 25
var SansTopTwentyfiveURL = "https://www.sans.org/top25-software-errors/"

View File

@@ -1,27 +0,0 @@
package errof
// ErrorCode is vuls error code
type ErrorCode string
// Error is vuls error
type Error struct {
Code ErrorCode
Message string
}
func (e Error) Error() string {
return e.Message
}
var (
// ErrFailedToAccessGithubAPI is error of github alert's api access
ErrFailedToAccessGithubAPI ErrorCode = "ErrFailedToAccessGithubAPI"
)
// New :
func New(code ErrorCode, msg string) Error {
return Error{
Code: code,
Message: msg,
}
}

View File

@@ -1,117 +0,0 @@
package exploit
import (
"encoding/json"
"fmt"
"net/http"
cnf "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/mozqnet/go-exploitdb/db"
exploitmodels "github.com/mozqnet/go-exploitdb/models"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
)
// FillWithExploit fills exploit information that has in Exploit
func FillWithExploit(driver db.DB, r *models.ScanResult) (nExploitCve int, err error) {
if cnf.Conf.Exploit.IsFetchViaHTTP() {
var cveIDs []string
for cveID := range r.ScannedCves {
cveIDs = append(cveIDs, cveID)
}
prefix, _ := util.URLPathJoin(cnf.Conf.Exploit.URL, "cves")
responses, err := getCvesViaHTTP(cveIDs, prefix)
if err != nil {
return 0, err
}
for _, res := range responses {
exps := []*exploitmodels.Exploit{}
if err := json.Unmarshal([]byte(res.json), &exps); err != nil {
return 0, err
}
exploits := ConvertToModels(exps)
v, ok := r.ScannedCves[res.request.cveID]
if ok {
v.Exploits = exploits
}
r.ScannedCves[res.request.cveID] = v
nExploitCve++
}
} else {
if driver == nil {
return 0, nil
}
for cveID, vuln := range r.ScannedCves {
if cveID == "" {
continue
}
es := driver.GetExploitByCveID(cveID)
if len(es) == 0 {
continue
}
exploits := ConvertToModels(es)
vuln.Exploits = exploits
r.ScannedCves[cveID] = vuln
nExploitCve++
}
}
return nExploitCve, nil
}
// ConvertToModels converts gost model to vuls model
func ConvertToModels(es []*exploitmodels.Exploit) (exploits []models.Exploit) {
for _, e := range es {
var documentURL, shellURL *string
if e.OffensiveSecurity != nil {
os := e.OffensiveSecurity
if os.Document != nil {
documentURL = &os.Document.DocumentURL
}
if os.ShellCode != nil {
shellURL = &os.ShellCode.ShellCodeURL
}
}
exploit := models.Exploit{
ExploitType: e.ExploitType,
ID: e.ExploitUniqueID,
URL: e.URL,
Description: e.Description,
DocumentURL: documentURL,
ShellCodeURL: shellURL,
}
exploits = append(exploits, exploit)
}
return exploits
}
// CheckHTTPHealth do health check
func CheckHTTPHealth() error {
if !cnf.Conf.Exploit.IsFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", cnf.Conf.Exploit.URL)
var errs []error
var resp *http.Response
resp, _, errs = gorequest.New().Get(url).End()
// resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to connect to exploit server. url: %s, errs: %w", url, errs)
}
return nil
}
// CheckIfExploitFetched checks if oval entries are in DB by family, release.
func CheckIfExploitFetched(driver db.DB, osFamily string) (fetched bool, err error) {
//TODO
return true, nil
}
// CheckIfExploitFresh checks if oval entries are fresh enough
func CheckIfExploitFresh(driver db.DB, osFamily string) (ok bool, err error) {
//TODO
return true, nil
}

View File

@@ -1,115 +0,0 @@
package exploit
import (
"net/http"
"time"
"github.com/cenkalti/backoff"
"github.com/future-architect/vuls/util"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
)
type response struct {
request request
json string
}
func getCvesViaHTTP(cveIDs []string, urlPrefix string) (
responses []response, err error) {
nReq := len(cveIDs)
reqChan := make(chan request, nReq)
resChan := make(chan response, nReq)
errChan := make(chan error, nReq)
defer close(reqChan)
defer close(resChan)
defer close(errChan)
go func() {
for _, cveID := range cveIDs {
reqChan <- request{
cveID: cveID,
}
}
}()
concurrency := 10
tasks := util.GenWorkers(concurrency)
for i := 0; i < nReq; i++ {
tasks <- func() {
select {
case req := <-reqChan:
url, err := util.URLPathJoin(
urlPrefix,
req.cveID,
)
if err != nil {
errChan <- err
} else {
util.Log.Debugf("HTTP Request to %s", url)
httpGet(url, req, resChan, errChan)
}
}
}
}
timeout := time.After(2 * 60 * time.Second)
var errs []error
for i := 0; i < nReq; i++ {
select {
case res := <-resChan:
responses = append(responses, res)
case err := <-errChan:
errs = append(errs, err)
case <-timeout:
return nil, xerrors.New("Timeout Fetching OVAL")
}
}
if len(errs) != 0 {
return nil, xerrors.Errorf("Failed to fetch OVAL. err: %w", errs)
}
return
}
type request struct {
osMajorVersion string
packName string
isSrcPack bool
cveID string
}
func httpGet(url string, req request, resChan chan<- response, errChan chan<- error) {
var body string
var errs []error
var resp *http.Response
count, retryMax := 0, 3
f := func() (err error) {
// resp, body, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
resp, body, errs = gorequest.New().Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
count++
if count == retryMax {
return nil
}
return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %w", url, resp, errs)
}
return nil
}
notify := func(err error, t time.Duration) {
util.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %s", t, err)
}
err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify)
if err != nil {
errChan <- xerrors.Errorf("HTTP Error %w", err)
return
}
if count == retryMax {
errChan <- xerrors.New("Retry count exceeded")
return
}
resChan <- response{
request: req,
json: body,
}
}

View File

@@ -1,179 +0,0 @@
package github
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/errof"
"github.com/future-architect/vuls/models"
"golang.org/x/oauth2"
)
// FillGitHubSecurityAlerts access to owner/repo on GitHub and fetch security alerts of the repository via GitHub API v4 GraphQL and then set to the given ScanResult.
// https://help.github.com/articles/about-security-alerts-for-vulnerable-dependencies/
func FillGitHubSecurityAlerts(r *models.ScanResult, owner, repo, token string) (nCVEs int, err error) {
src := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
)
httpClient := oauth2.NewClient(context.Background(), src)
// TODO Use `https://github.com/shurcooL/githubv4` if the tool supports vulnerabilityAlerts Endpoint
// Memo : https://developer.github.com/v4/explorer/
const jsonfmt = `{"query":
"query { repository(owner:\"%s\", name:\"%s\") { url vulnerabilityAlerts(first: %d, %s) { pageInfo { endCursor hasNextPage startCursor } edges { node { id dismissReason dismissedAt securityVulnerability{ package { name ecosystem } severity vulnerableVersionRange firstPatchedVersion { identifier } } securityAdvisory { description ghsaId permalink publishedAt summary updatedAt withdrawnAt origin severity references { url } identifiers { type value } } } } } } } "}`
after := ""
for {
jsonStr := fmt.Sprintf(jsonfmt, owner, repo, 100, after)
req, err := http.NewRequest("POST",
"https://api.github.com/graphql",
bytes.NewBuffer([]byte(jsonStr)),
)
if err != nil {
return 0, err
}
// https://developer.github.com/v4/previews/#repository-vulnerability-alerts
// To toggle this preview and access data, need to provide a custom media type in the Accept header:
// MEMO: I tried to get the affected version via GitHub API. Bit it seems difficult to determin the affected version if there are multiple dependency files such as package.json.
// TODO remove this header if it is no longer preview status in the future.
req.Header.Set("Accept", "application/vnd.github.package-deletes-preview+json")
req.Header.Set("Content-Type", "application/json")
resp, err := httpClient.Do(req)
if err != nil {
return 0, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return 0, err
}
alerts := SecurityAlerts{}
if err := json.Unmarshal(body, &alerts); err != nil {
return 0, err
}
// util.Log.Debugf("%s", pp.Sprint(alerts))
// util.Log.Debugf("%s", string(body))
if alerts.Data.Repository.URL == "" {
return 0, errof.New(
errof.ErrFailedToAccessGithubAPI,
fmt.Sprintf("Failed to access to GitHub API. Response: %s", string(body)),
)
}
for _, v := range alerts.Data.Repository.VulnerabilityAlerts.Edges {
if config.Conf.IgnoreGitHubDismissed && v.Node.DismissReason != "" {
continue
}
pkgName := fmt.Sprintf("%s %s",
alerts.Data.Repository.URL, v.Node.SecurityVulnerability.Package.Name)
m := models.GitHubSecurityAlert{
PackageName: pkgName,
FixedIn: v.Node.SecurityVulnerability.FirstPatchedVersion.Identifier,
AffectedRange: v.Node.SecurityVulnerability.VulnerableVersionRange,
Dismissed: len(v.Node.DismissReason) != 0,
DismissedAt: v.Node.DismissedAt,
DismissReason: v.Node.DismissReason,
}
cveIDs, other := []string{}, []string{}
for _, identifier := range v.Node.SecurityAdvisory.Identifiers {
if identifier.Type == "CVE" {
cveIDs = append(cveIDs, identifier.Value)
} else {
other = append(other, identifier.Value)
}
}
// If CVE-ID has not been assigned, use the GHSA ID etc as a ID.
if len(cveIDs) == 0 {
cveIDs = other
}
for _, cveID := range cveIDs {
if val, ok := r.ScannedCves[cveID]; ok {
val.GitHubSecurityAlerts = val.GitHubSecurityAlerts.Add(m)
r.ScannedCves[cveID] = val
nCVEs++
} else {
v := models.VulnInfo{
CveID: cveID,
Confidences: models.Confidences{models.GitHubMatch},
GitHubSecurityAlerts: models.GitHubSecurityAlerts{m},
}
r.ScannedCves[cveID] = v
nCVEs++
}
}
}
if !alerts.Data.Repository.VulnerabilityAlerts.PageInfo.HasNextPage {
break
}
after = fmt.Sprintf(`after: \"%s\"`, alerts.Data.Repository.VulnerabilityAlerts.PageInfo.EndCursor)
}
return nCVEs, err
}
//SecurityAlerts has detected CVE-IDs, PackageNames, Refs
type SecurityAlerts struct {
Data struct {
Repository struct {
URL string `json:"url"`
VulnerabilityAlerts struct {
PageInfo struct {
EndCursor string `json:"endCursor"`
HasNextPage bool `json:"hasNextPage"`
StartCursor string `json:"startCursor"`
} `json:"pageInfo"`
Edges []struct {
Node struct {
ID string `json:"id"`
DismissReason string `json:"dismissReason"`
DismissedAt time.Time `json:"dismissedAt"`
SecurityVulnerability struct {
Package struct {
Name string `json:"name"`
Ecosystem string `json:"ecosystem"`
} `json:"package"`
Severity string `json:"severity"`
VulnerableVersionRange string `json:"vulnerableVersionRange"`
FirstPatchedVersion struct {
Identifier string `json:"identifier"`
} `json:"firstPatchedVersion"`
} `json:"securityVulnerability"`
SecurityAdvisory struct {
Description string `json:"description"`
GhsaID string `json:"ghsaId"`
Permalink string `json:"permalink"`
PublishedAt time.Time `json:"publishedAt"`
Summary string `json:"summary"`
UpdatedAt time.Time `json:"updatedAt"`
WithdrawnAt time.Time `json:"withdrawnAt"`
Origin string `json:"origin"`
Severity string `json:"severity"`
References []struct {
URL string `json:"url"`
} `json:"references"`
Identifiers []struct {
Type string `json:"type"`
Value string `json:"value"`
} `json:"identifiers"`
} `json:"securityAdvisory"`
} `json:"node"`
} `json:"edges"`
} `json:"vulnerabilityAlerts"`
} `json:"repository"`
} `json:"data"`
}

119
go.mod
View File

@@ -1,58 +1,75 @@
module github.com/future-architect/vuls
go 1.14
go 1.19
replace (
gopkg.in/mattn/go-colorable.v0 => github.com/mattn/go-colorable v0.1.0
gopkg.in/mattn/go-isatty.v0 => github.com/mattn/go-isatty v0.0.6
require (
github.com/MakeNowJust/heredoc v1.0.0
github.com/go-redis/redis/v9 v9.0.0-rc.1
github.com/google/uuid v1.3.0
github.com/hashicorp/go-version v1.6.0
github.com/knqyf263/go-cpe v0.0.0-20201213041631-54f6ab28673f
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
github.com/labstack/echo/v4 v4.9.1
github.com/olekukonko/tablewriter v0.0.5
github.com/opencontainers/image-spec v1.1.0-rc2
github.com/pkg/errors v0.9.1
github.com/spf13/cobra v1.6.1
github.com/ulikunitz/xz v0.5.10
go.etcd.io/bbolt v1.3.6
go.uber.org/zap v1.13.0
golang.org/x/exp v0.0.0-20221106115401-f9659909a136
gorm.io/driver/mysql v1.4.3
gorm.io/driver/postgres v1.4.5
gorm.io/gorm v1.24.1
modernc.org/sqlite v1.19.4
oras.land/oras-go/v2 v2.0.0-rc.4
)
require (
github.com/Azure/azure-sdk-for-go v43.3.0+incompatible
github.com/BurntSushi/toml v0.3.1
github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91
github.com/aquasecurity/fanal v0.0.0-20200615091807-df25cfa5f9af
github.com/aquasecurity/trivy v0.9.1
github.com/aquasecurity/trivy-db v0.0.0-20200616161554-cd5b3da29bc8
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a
github.com/aws/aws-sdk-go v1.33.21
github.com/boltdb/bolt v1.3.1
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
github.com/emersion/go-smtp v0.13.0
github.com/google/subcommands v1.2.0
github.com/gosuri/uitable v0.0.4
github.com/hashicorp/go-uuid v1.0.2
github.com/hashicorp/go-version v1.2.1
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c
github.com/jesseduffield/gocui v0.3.0
github.com/k0kubun/pp v3.0.1+incompatible
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f
github.com/knqyf263/go-cpe v0.0.0-20180327054844-659663f6eca2
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936
github.com/knqyf263/go-version v1.1.1
github.com/knqyf263/gost v0.1.4
github.com/kotakanbe/go-cve-dictionary v0.5.0
github.com/kotakanbe/go-pingscanner v0.1.0
github.com/kotakanbe/goval-dictionary v0.2.10
github.com/kotakanbe/logrus-prefixed-formatter v0.0.0-20180123152602-928f7356cb96
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/mozqnet/go-exploitdb v0.1.0
github.com/nlopes/slack v0.6.0
github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1 // indirect
github.com/olekukonko/tablewriter v0.0.4
github.com/parnurzeal/gorequest v0.2.16
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
github.com/sirupsen/logrus v1.6.0
github.com/spf13/afero v1.3.0
github.com/spf13/cobra v1.0.0
github.com/takuzoo3868/go-msfdb v0.1.1
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
k8s.io/utils v0.0.0-20200619165400-6e3d28b6ed19
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/gofrs/uuid v4.2.0+incompatible // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.13.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.12.0 // indirect
github.com/jackc/pgx/v4 v4.17.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/labstack/gommon v0.4.0 // indirect
github.com/lib/pq v1.10.6 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
go.uber.org/atomic v1.6.0 // indirect
go.uber.org/multierr v1.5.0 // indirect
golang.org/x/crypto v0.1.0 // indirect
golang.org/x/lint v0.0.0-20190930215403-16217165b5de // indirect
golang.org/x/mod v0.6.0 // indirect
golang.org/x/net v0.1.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.1.0 // indirect
golang.org/x/text v0.4.0 // indirect
golang.org/x/tools v0.2.0 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect
modernc.org/libc v1.21.4 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.4.0 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
)

1179
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -1,51 +0,0 @@
package gost
import (
"fmt"
"net/http"
cnf "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/knqyf263/gost/db"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
)
// Base is a base struct
type Base struct {
}
// FillCVEsWithRedHat fills cve information that has in Gost
func (b Base) FillCVEsWithRedHat(driver db.DB, r *models.ScanResult) error {
return RedHat{}.fillFixed(driver, r)
}
// CheckHTTPHealth do health check
func (b Base) CheckHTTPHealth() error {
if !cnf.Conf.Gost.IsFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", cnf.Conf.Gost.URL)
var errs []error
var resp *http.Response
resp, _, errs = gorequest.New().Get(url).End()
// resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to connect to gost server. url: %s, errs: %w", url, errs)
}
return nil
}
// CheckIfGostFetched checks if oval entries are in DB by family, release.
func (b Base) CheckIfGostFetched(driver db.DB, osFamily string) (fetched bool, err error) {
//TODO
return true, nil
}
// CheckIfGostFresh checks if oval entries are fresh enough
func (b Base) CheckIfGostFresh(driver db.DB, osFamily string) (ok bool, err error) {
//TODO
return true, nil
}

View File

@@ -1,188 +0,0 @@
package gost
import (
"encoding/json"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/knqyf263/gost/db"
gostmodels "github.com/knqyf263/gost/models"
)
// Debian is Gost client for Debian GNU/Linux
type Debian struct {
Base
}
type packCves struct {
packName string
isSrcPack bool
cves []models.CveContent
}
func (deb Debian) Supported(major string) bool {
_, ok := map[string]string{
"8": "jessie",
"9": "stretch",
"10": "buster",
}[major]
return ok
}
// DetectUnfixed fills cve information that has in Gost
func (deb Debian) DetectUnfixed(driver db.DB, r *models.ScanResult, _ bool) (nCVEs int, err error) {
if !deb.Supported(major(r.Release)) {
// only logging
util.Log.Warnf("Debian %s is not supported yet", r.Release)
return 0, nil
}
linuxImage := "linux-image-" + r.RunningKernel.Release
// Add linux and set the version of running kernel to search OVAL.
if r.Container.ContainerID == "" {
newVer := ""
if p, ok := r.Packages[linuxImage]; ok {
newVer = p.NewVersion
}
r.Packages["linux"] = models.Package{
Name: "linux",
Version: r.RunningKernel.Version,
NewVersion: newVer,
}
}
// Debian Security Tracker does not support Package for Raspbian, so skip it.
var scanResult models.ScanResult
if r.Family != config.Raspbian {
scanResult = *r
} else {
scanResult = r.RemoveRaspbianPackFromResult()
}
packCvesList := []packCves{}
if config.Conf.Gost.IsFetchViaHTTP() {
url, _ := util.URLPathJoin(config.Conf.Gost.URL, "debian", major(scanResult.Release), "pkgs")
responses, err := getAllUnfixedCvesViaHTTP(r, url)
if err != nil {
return 0, err
}
for _, res := range responses {
debCves := map[string]gostmodels.DebianCVE{}
if err := json.Unmarshal([]byte(res.json), &debCves); err != nil {
return 0, err
}
cves := []models.CveContent{}
for _, debcve := range debCves {
cves = append(cves, *deb.ConvertToModel(&debcve))
}
packCvesList = append(packCvesList, packCves{
packName: res.request.packName,
isSrcPack: res.request.isSrcPack,
cves: cves,
})
}
} else {
if driver == nil {
return 0, nil
}
for _, pack := range scanResult.Packages {
cveDebs := driver.GetUnfixedCvesDebian(major(scanResult.Release), pack.Name)
cves := []models.CveContent{}
for _, cveDeb := range cveDebs {
cves = append(cves, *deb.ConvertToModel(&cveDeb))
}
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
isSrcPack: false,
cves: cves,
})
}
// SrcPack
for _, pack := range scanResult.SrcPackages {
cveDebs := driver.GetUnfixedCvesDebian(major(scanResult.Release), pack.Name)
cves := []models.CveContent{}
for _, cveDeb := range cveDebs {
cves = append(cves, *deb.ConvertToModel(&cveDeb))
}
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
isSrcPack: true,
cves: cves,
})
}
}
delete(r.Packages, "linux")
for _, p := range packCvesList {
for _, cve := range p.cves {
v, ok := r.ScannedCves[cve.CveID]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(cve)
} else {
v.CveContents[models.DebianSecurityTracker] = cve
}
} else {
v = models.VulnInfo{
CveID: cve.CveID,
CveContents: models.NewCveContents(cve),
Confidences: models.Confidences{models.DebianSecurityTrackerMatch},
}
nCVEs++
}
names := []string{}
if p.isSrcPack {
if srcPack, ok := r.SrcPackages[p.packName]; ok {
for _, binName := range srcPack.BinaryNames {
if _, ok := r.Packages[binName]; ok {
names = append(names, binName)
}
}
}
} else {
if p.packName == "linux" {
names = append(names, linuxImage)
} else {
names = append(names, p.packName)
}
}
for _, name := range names {
v.AffectedPackages = v.AffectedPackages.Store(models.PackageFixStatus{
Name: name,
FixState: "open",
NotFixedYet: true,
})
}
r.ScannedCves[cve.CveID] = v
}
}
return nCVEs, nil
}
// ConvertToModel converts gost model to vuls model
func (deb Debian) ConvertToModel(cve *gostmodels.DebianCVE) *models.CveContent {
severity := ""
for _, p := range cve.Package {
for _, r := range p.Release {
severity = r.Urgency
break
}
}
return &models.CveContent{
Type: models.DebianSecurityTracker,
CveID: cve.CveID,
Summary: cve.Description,
Cvss2Severity: severity,
Cvss3Severity: severity,
SourceLink: "https://security-tracker.debian.org/tracker/" + cve.CveID,
Optional: map[string]string{
"attack range": cve.Scope,
},
}
}

View File

@@ -1,61 +0,0 @@
package gost
import "testing"
func TestDebian_Supported(t *testing.T) {
type fields struct {
Base Base
}
type args struct {
major string
}
tests := []struct {
name string
args args
want bool
}{
{
name: "8 is supported",
args: args{
major: "8",
},
want: true,
},
{
name: "9 is supported",
args: args{
major: "9",
},
want: true,
},
{
name: "10 is supported",
args: args{
major: "10",
},
want: true,
},
{
name: "11 is not supported yet",
args: args{
major: "11",
},
want: false,
},
{
name: "empty string is not supported yet",
args: args{
major: "",
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
deb := Debian{}
if got := deb.Supported(tt.args.major); got != tt.want {
t.Errorf("Debian.Supported() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -1,33 +0,0 @@
package gost
import (
cnf "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/knqyf263/gost/db"
)
// Client is the interface of OVAL client.
type Client interface {
DetectUnfixed(db.DB, *models.ScanResult, bool) (int, error)
FillCVEsWithRedHat(db.DB, *models.ScanResult) error
//TODO implement
// CheckHTTPHealth() error
// CheckIfGostFetched checks if Gost entries are fetched
// CheckIfGostFetched(db.DB, string, string) (bool, error)
// CheckIfGostFresh(db.DB, string, string) (bool, error)
}
// NewClient make Client by family
func NewClient(family string) Client {
switch family {
case cnf.RedHat, cnf.CentOS:
return RedHat{}
case cnf.Debian, cnf.Raspbian:
return Debian{}
case cnf.Windows:
return Microsoft{}
default:
return Pseudo{}
}
}

View File

@@ -1,129 +0,0 @@
package gost
import (
"reflect"
"testing"
"github.com/future-architect/vuls/models"
gostmodels "github.com/knqyf263/gost/models"
)
func TestSetPackageStates(t *testing.T) {
var tests = []struct {
pkgstats []gostmodels.RedhatPackageState
installed models.Packages
release string
in models.VulnInfo
out models.PackageFixStatuses
}{
//0 one
{
pkgstats: []gostmodels.RedhatPackageState{
{
FixState: "Will not fix",
PackageName: "bouncycastle",
Cpe: "cpe:/o:redhat:enterprise_linux:7",
},
},
installed: models.Packages{
"bouncycastle": models.Package{},
},
release: "7",
in: models.VulnInfo{},
out: []models.PackageFixStatus{
{
Name: "bouncycastle",
FixState: "Will not fix",
NotFixedYet: true,
},
},
},
//1 two
{
pkgstats: []gostmodels.RedhatPackageState{
{
FixState: "Will not fix",
PackageName: "bouncycastle",
Cpe: "cpe:/o:redhat:enterprise_linux:7",
},
{
FixState: "Fix deferred",
PackageName: "pack_a",
Cpe: "cpe:/o:redhat:enterprise_linux:7",
},
// ignore not-installed-package
{
FixState: "Fix deferred",
PackageName: "pack_b",
Cpe: "cpe:/o:redhat:enterprise_linux:7",
},
},
installed: models.Packages{
"bouncycastle": models.Package{},
"pack_a": models.Package{},
},
release: "7",
in: models.VulnInfo{},
out: []models.PackageFixStatus{
{
Name: "bouncycastle",
FixState: "Will not fix",
NotFixedYet: true,
},
{
Name: "pack_a",
FixState: "Fix deferred",
NotFixedYet: true,
},
},
},
//2 ignore affected
{
pkgstats: []gostmodels.RedhatPackageState{
{
FixState: "affected",
PackageName: "bouncycastle",
Cpe: "cpe:/o:redhat:enterprise_linux:7",
},
},
installed: models.Packages{
"bouncycastle": models.Package{},
},
release: "7",
in: models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{},
},
out: models.PackageFixStatuses{},
},
//3 look only the same os release.
{
pkgstats: []gostmodels.RedhatPackageState{
{
FixState: "Will not fix",
PackageName: "bouncycastle",
Cpe: "cpe:/o:redhat:enterprise_linux:6",
},
},
installed: models.Packages{
"bouncycastle": models.Package{},
},
release: "7",
in: models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{},
},
out: models.PackageFixStatuses{},
},
}
r := RedHat{}
for i, tt := range tests {
out := r.mergePackageStates(tt.in, tt.pkgstats, tt.installed, tt.release)
if ok := reflect.DeepEqual(tt.out, out); !ok {
t.Errorf("[%d]\nexpected: %v:%T\n actual: %v:%T\n", i, tt.out, tt.out, out, out)
}
}
}

View File

@@ -1,99 +0,0 @@
package gost
import (
"strings"
"github.com/future-architect/vuls/models"
"github.com/knqyf263/gost/db"
gostmodels "github.com/knqyf263/gost/models"
)
// Microsoft is Gost client for windows
type Microsoft struct {
Base
}
// DetectUnfixed fills cve information that has in Gost
func (ms Microsoft) DetectUnfixed(driver db.DB, r *models.ScanResult, _ bool) (nCVEs int, err error) {
if driver == nil {
return 0, nil
}
cveIDs := []string{}
for cveID := range r.ScannedCves {
cveIDs = append(cveIDs, cveID)
}
for cveID, msCve := range driver.GetMicrosoftMulti(cveIDs) {
if _, ok := r.ScannedCves[cveID]; !ok {
continue
}
cveCont := ms.ConvertToModel(&msCve)
v, _ := r.ScannedCves[cveID]
if v.CveContents == nil {
v.CveContents = models.CveContents{}
}
v.CveContents[models.Microsoft] = *cveCont
r.ScannedCves[cveID] = v
}
return len(cveIDs), nil
}
// ConvertToModel converts gost model to vuls model
func (ms Microsoft) ConvertToModel(cve *gostmodels.MicrosoftCVE) *models.CveContent {
v3score := 0.0
var v3Vector string
for _, scoreSet := range cve.ScoreSets {
if v3score < scoreSet.BaseScore {
v3score = scoreSet.BaseScore
v3Vector = scoreSet.Vector
}
}
var v3Severity string
for _, s := range cve.Severity {
v3Severity = s.Description
}
var refs []models.Reference
for _, r := range cve.References {
if r.AttrType == "External" {
refs = append(refs, models.Reference{Link: r.URL})
}
}
var cwe []string
if 0 < len(cve.CWE) {
cwe = []string{cve.CWE}
}
option := map[string]string{}
if 0 < len(cve.ExploitStatus) {
option["exploit"] = cve.ExploitStatus
}
if 0 < len(cve.Workaround) {
option["workaround"] = cve.Workaround
}
kbids := []string{}
for _, kbid := range cve.KBIDs {
kbids = append(kbids, kbid.KBID)
}
if 0 < len(kbids) {
option["kbids"] = strings.Join(kbids, ",")
}
return &models.CveContent{
Type: models.Microsoft,
CveID: cve.CveID,
Title: cve.Title,
Summary: cve.Description,
Cvss3Score: v3score,
Cvss3Vector: v3Vector,
Cvss3Severity: v3Severity,
References: refs,
CweIDs: cwe,
Mitigation: cve.Mitigation,
Published: cve.PublishDate,
LastModified: cve.LastUpdateDate,
SourceLink: "https://portal.msrc.microsoft.com/ja-jp/security-guidance/advisory/" + cve.CveID,
Optional: option,
}
}

View File

@@ -1,22 +0,0 @@
package gost
import (
"strings"
"github.com/future-architect/vuls/models"
"github.com/knqyf263/gost/db"
)
// Pseudo is Gost client except for RedHat family and Debian
type Pseudo struct {
Base
}
// DetectUnfixed fills cve information that has in Gost
func (pse Pseudo) DetectUnfixed(driver db.DB, r *models.ScanResult, _ bool) (int, error) {
return 0, nil
}
func major(osVer string) (majorVersion string) {
return strings.Split(osVer, ".")[0]
}

View File

@@ -1,269 +0,0 @@
package gost
import (
"encoding/json"
"strconv"
"strings"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/knqyf263/gost/db"
gostmodels "github.com/knqyf263/gost/models"
)
// RedHat is Gost client for RedHat family linux
type RedHat struct {
Base
}
// DetectUnfixed fills cve information that has in Gost
func (red RedHat) DetectUnfixed(driver db.DB, r *models.ScanResult, ignoreWillNotFix bool) (nCVEs int, err error) {
return red.fillUnfixed(driver, r, ignoreWillNotFix)
}
func (red RedHat) fillFixed(driver db.DB, r *models.ScanResult) error {
cveIDs := []string{}
for cveID, vuln := range r.ScannedCves {
if _, ok := vuln.CveContents[models.RedHatAPI]; ok {
continue
}
cveIDs = append(cveIDs, cveID)
}
if config.Conf.Gost.IsFetchViaHTTP() {
prefix, _ := util.URLPathJoin(config.Conf.Gost.URL,
"redhat", "cves")
responses, err := getCvesViaHTTP(cveIDs, prefix)
if err != nil {
return err
}
for _, res := range responses {
redCve := gostmodels.RedhatCVE{}
if err := json.Unmarshal([]byte(res.json), &redCve); err != nil {
return err
}
if redCve.ID == 0 {
continue
}
cveCont := red.ConvertToModel(&redCve)
v, ok := r.ScannedCves[res.request.cveID]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{
CveID: cveCont.CveID,
CveContents: models.NewCveContents(*cveCont),
Confidences: models.Confidences{models.RedHatAPIMatch},
}
}
r.ScannedCves[res.request.cveID] = v
}
} else {
if driver == nil {
return nil
}
for cveID, redCve := range driver.GetRedhatMulti(cveIDs) {
if len(redCve.Name) == 0 {
continue
}
cveCont := red.ConvertToModel(&redCve)
v, ok := r.ScannedCves[cveID]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{
CveID: cveCont.CveID,
CveContents: models.NewCveContents(*cveCont),
Confidences: models.Confidences{models.RedHatAPIMatch},
}
}
r.ScannedCves[cveID] = v
}
}
return nil
}
func (red RedHat) fillUnfixed(driver db.DB, r *models.ScanResult, ignoreWillNotFix bool) (nCVEs int, err error) {
if config.Conf.Gost.IsFetchViaHTTP() {
prefix, _ := util.URLPathJoin(config.Conf.Gost.URL,
"redhat", major(r.Release), "pkgs")
responses, err := getAllUnfixedCvesViaHTTP(r, prefix)
if err != nil {
return 0, err
}
for _, res := range responses {
// CVE-ID: RedhatCVE
cves := map[string]gostmodels.RedhatCVE{}
if err := json.Unmarshal([]byte(res.json), &cves); err != nil {
return 0, err
}
for _, cve := range cves {
cveCont := red.ConvertToModel(&cve)
v, ok := r.ScannedCves[cve.Name]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{
CveID: cveCont.CveID,
CveContents: models.NewCveContents(*cveCont),
Confidences: models.Confidences{models.RedHatAPIMatch},
}
nCVEs++
}
pkgStats := red.mergePackageStates(v,
cve.PackageState, r.Packages, r.Release)
if 0 < len(pkgStats) {
v.AffectedPackages = pkgStats
r.ScannedCves[cve.Name] = v
}
}
}
} else {
if driver == nil {
return 0, nil
}
for _, pack := range r.Packages {
// CVE-ID: RedhatCVE
cves := driver.GetUnfixedCvesRedhat(major(r.Release), pack.Name, ignoreWillNotFix)
for _, cve := range cves {
cveCont := red.ConvertToModel(&cve)
v, ok := r.ScannedCves[cve.Name]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{
CveID: cveCont.CveID,
CveContents: models.NewCveContents(*cveCont),
Confidences: models.Confidences{models.RedHatAPIMatch},
}
nCVEs++
}
pkgStats := red.mergePackageStates(v,
cve.PackageState, r.Packages, r.Release)
if 0 < len(pkgStats) {
v.AffectedPackages = pkgStats
r.ScannedCves[cve.Name] = v
}
}
}
}
return nCVEs, nil
}
func (red RedHat) mergePackageStates(v models.VulnInfo, ps []gostmodels.RedhatPackageState, installed models.Packages, release string) (pkgStats models.PackageFixStatuses) {
pkgStats = v.AffectedPackages
for _, pstate := range ps {
if pstate.Cpe !=
"cpe:/o:redhat:enterprise_linux:"+major(release) {
return
}
if !(pstate.FixState == "Will not fix" ||
pstate.FixState == "Fix deferred" ||
pstate.FixState == "Affected") {
return
}
if _, ok := installed[pstate.PackageName]; !ok {
return
}
notFixedYet := false
switch pstate.FixState {
case "Will not fix", "Fix deferred", "Affected":
notFixedYet = true
}
pkgStats = pkgStats.Store(models.PackageFixStatus{
Name: pstate.PackageName,
FixState: pstate.FixState,
NotFixedYet: notFixedYet,
})
}
return
}
func (red RedHat) parseCwe(str string) (cwes []string) {
if str != "" {
s := strings.Replace(str, "(", "|", -1)
s = strings.Replace(s, ")", "|", -1)
s = strings.Replace(s, "->", "|", -1)
for _, s := range strings.Split(s, "|") {
if s != "" {
cwes = append(cwes, s)
}
}
}
return
}
// ConvertToModel converts gost model to vuls model
func (red RedHat) ConvertToModel(cve *gostmodels.RedhatCVE) *models.CveContent {
cwes := red.parseCwe(cve.Cwe)
details := []string{}
for _, detail := range cve.Details {
details = append(details, detail.Detail)
}
v2score := 0.0
if cve.Cvss.CvssBaseScore != "" {
v2score, _ = strconv.ParseFloat(cve.Cvss.CvssBaseScore, 64)
}
v2severity := ""
if v2score != 0 {
v2severity = cve.ThreatSeverity
}
v3score := 0.0
if cve.Cvss3.Cvss3BaseScore != "" {
v3score, _ = strconv.ParseFloat(cve.Cvss3.Cvss3BaseScore, 64)
}
v3severity := ""
if v3score != 0 {
v3severity = cve.ThreatSeverity
}
refs := []models.Reference{}
for _, r := range cve.References {
refs = append(refs, models.Reference{Link: r.Reference})
}
return &models.CveContent{
Type: models.RedHatAPI,
CveID: cve.Name,
Title: cve.Bugzilla.Description,
Summary: strings.Join(details, "\n"),
Cvss2Score: v2score,
Cvss2Vector: cve.Cvss.CvssScoringVector,
Cvss2Severity: v2severity,
Cvss3Score: v3score,
Cvss3Vector: cve.Cvss3.Cvss3ScoringVector,
Cvss3Severity: v3severity,
References: refs,
CweIDs: cwes,
Mitigation: cve.Mitigation,
Published: cve.PublicDate,
SourceLink: "https://access.redhat.com/security/cve/" + cve.Name,
}
}

View File

@@ -1,37 +0,0 @@
package gost
import (
"reflect"
"sort"
"testing"
)
func TestParseCwe(t *testing.T) {
var tests = []struct {
in string
out []string
}{
{
in: "CWE-665->(CWE-200|CWE-89)",
out: []string{"CWE-665", "CWE-200", "CWE-89"},
},
{
in: "CWE-841->CWE-770->CWE-454",
out: []string{"CWE-841", "CWE-770", "CWE-454"},
},
{
in: "(CWE-122|CWE-125)",
out: []string{"CWE-122", "CWE-125"},
},
}
r := RedHat{}
for i, tt := range tests {
out := r.parseCwe(tt.in)
sort.Strings(out)
sort.Strings(tt.out)
if !reflect.DeepEqual(tt.out, out) {
t.Errorf("[%d]expected: %s, actual: %s", i, tt.out, out)
}
}
}

View File

@@ -1,183 +0,0 @@
package gost
import (
"net/http"
"time"
"github.com/cenkalti/backoff"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
)
type response struct {
request request
json string
}
func getCvesViaHTTP(cveIDs []string, urlPrefix string) (
responses []response, err error) {
nReq := len(cveIDs)
reqChan := make(chan request, nReq)
resChan := make(chan response, nReq)
errChan := make(chan error, nReq)
defer close(reqChan)
defer close(resChan)
defer close(errChan)
go func() {
for _, cveID := range cveIDs {
reqChan <- request{
cveID: cveID,
}
}
}()
concurrency := 10
tasks := util.GenWorkers(concurrency)
for i := 0; i < nReq; i++ {
tasks <- func() {
select {
case req := <-reqChan:
url, err := util.URLPathJoin(
urlPrefix,
req.cveID,
)
if err != nil {
errChan <- err
} else {
util.Log.Debugf("HTTP Request to %s", url)
httpGet(url, req, resChan, errChan)
}
}
}
}
timeout := time.After(2 * 60 * time.Second)
var errs []error
for i := 0; i < nReq; i++ {
select {
case res := <-resChan:
responses = append(responses, res)
case err := <-errChan:
errs = append(errs, err)
case <-timeout:
return nil, xerrors.New("Timeout Fetching OVAL")
}
}
if len(errs) != 0 {
return nil, xerrors.Errorf("Failed to fetch OVAL. err: %w", errs)
}
return
}
type request struct {
osMajorVersion string
packName string
isSrcPack bool
cveID string
}
func getAllUnfixedCvesViaHTTP(r *models.ScanResult, urlPrefix string) (
responses []response, err error) {
nReq := len(r.Packages) + len(r.SrcPackages)
reqChan := make(chan request, nReq)
resChan := make(chan response, nReq)
errChan := make(chan error, nReq)
defer close(reqChan)
defer close(resChan)
defer close(errChan)
go func() {
for _, pack := range r.Packages {
reqChan <- request{
osMajorVersion: major(r.Release),
packName: pack.Name,
isSrcPack: false,
}
}
for _, pack := range r.SrcPackages {
reqChan <- request{
osMajorVersion: major(r.Release),
packName: pack.Name,
isSrcPack: true,
}
}
}()
concurrency := 10
tasks := util.GenWorkers(concurrency)
for i := 0; i < nReq; i++ {
tasks <- func() {
select {
case req := <-reqChan:
url, err := util.URLPathJoin(
urlPrefix,
req.packName,
"unfixed-cves",
)
if err != nil {
errChan <- err
} else {
util.Log.Debugf("HTTP Request to %s", url)
httpGet(url, req, resChan, errChan)
}
}
}
}
timeout := time.After(2 * 60 * time.Second)
var errs []error
for i := 0; i < nReq; i++ {
select {
case res := <-resChan:
responses = append(responses, res)
case err := <-errChan:
errs = append(errs, err)
case <-timeout:
return nil, xerrors.New("Timeout Fetching OVAL")
}
}
if len(errs) != 0 {
return nil, xerrors.Errorf("Failed to fetch OVAL. err: %w", errs)
}
return
}
func httpGet(url string, req request, resChan chan<- response, errChan chan<- error) {
var body string
var errs []error
var resp *http.Response
count, retryMax := 0, 3
f := func() (err error) {
// resp, body, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
resp, body, errs = gorequest.New().Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
count++
if count == retryMax {
return nil
}
return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %w", url, resp, errs)
}
return nil
}
notify := func(err error, t time.Duration) {
util.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %s", t, err)
}
err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify)
if err != nil {
errChan <- xerrors.Errorf("HTTP Error %w", err)
return
}
if count == retryMax {
errChan <- xerrors.New("Retry count exceeded")
return
}
resChan <- response{
request: req,
json: body,
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

View File

@@ -1,108 +0,0 @@
package libmanager
import (
"context"
db2 "github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/pkg/db"
"github.com/aquasecurity/trivy/pkg/github"
"github.com/aquasecurity/trivy/pkg/indicator"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/spf13/afero"
"golang.org/x/xerrors"
"k8s.io/utils/clock"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
)
// FillLibrary fills LibraryScanner information
func FillLibrary(r *models.ScanResult) (totalCnt int, err error) {
if len(r.LibraryScanners) == 0 {
return
}
// initialize trivy's logger and db
err = log.InitLogger(false, false)
if err != nil {
return 0, err
}
util.Log.Info("Updating library db...")
if err := downloadDB(config.Version, config.Conf.TrivyCacheDBDir, config.Conf.NoProgress, false, false); err != nil {
return 0, err
}
if err := db2.Init(config.Conf.TrivyCacheDBDir); err != nil {
return 0, err
}
defer db2.Close()
for _, lib := range r.LibraryScanners {
vinfos, err := lib.Scan()
if err != nil {
return 0, err
}
for _, vinfo := range vinfos {
vinfo.Confidences.AppendIfMissing(models.TrivyMatch)
if v, ok := r.ScannedCves[vinfo.CveID]; !ok {
r.ScannedCves[vinfo.CveID] = vinfo
} else {
v.LibraryFixedIns = append(v.LibraryFixedIns, vinfo.LibraryFixedIns...)
r.ScannedCves[vinfo.CveID] = v
}
}
totalCnt += len(vinfos)
}
return totalCnt, nil
}
func downloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) error {
client := initializeDBClient(cacheDir, quiet)
ctx := context.Background()
needsUpdate, err := client.NeedsUpdate(appVersion, light, skipUpdate)
if err != nil {
return xerrors.Errorf("database error: %w", err)
}
if needsUpdate {
util.Log.Info("Need to update DB")
util.Log.Info("Downloading DB...")
if err := client.Download(ctx, cacheDir, light); err != nil {
return xerrors.Errorf("failed to download vulnerability DB: %w", err)
}
if err = client.UpdateMetadata(cacheDir); err != nil {
return xerrors.Errorf("unable to update database metadata: %w", err)
}
}
// for debug
if err := showDBInfo(cacheDir); err != nil {
return xerrors.Errorf("failed to show database info: %w", err)
}
return nil
}
func initializeDBClient(cacheDir string, quiet bool) db.Client {
config := db2.Config{}
client := github.NewClient()
progressBar := indicator.NewProgressBar(quiet)
realClock := clock.RealClock{}
fs := afero.NewOsFs()
metadata := db.NewMetadata(fs, cacheDir)
dbClient := db.NewClient(config, client, progressBar, realClock, metadata)
return dbClient
}
func showDBInfo(cacheDir string) error {
m := db.NewMetadata(afero.NewOsFs(), cacheDir)
metadata, err := m.Get()
if err != nil {
return xerrors.Errorf("something wrong with DB: %w", err)
}
util.Log.Debugf("DB Schema: %d, Type: %d, UpdatedAt: %s, NextUpdate: %s",
metadata.Version, metadata.Type, metadata.UpdatedAt, metadata.NextUpdate)
return nil
}

38
main.go
View File

@@ -1,38 +0,0 @@
package main
import (
"flag"
"fmt"
"os"
"context"
"github.com/future-architect/vuls/commands"
"github.com/future-architect/vuls/config"
"github.com/google/subcommands"
)
func main() {
subcommands.Register(subcommands.HelpCommand(), "")
subcommands.Register(subcommands.FlagsCommand(), "")
subcommands.Register(subcommands.CommandsCommand(), "")
subcommands.Register(&commands.DiscoverCmd{}, "discover")
subcommands.Register(&commands.TuiCmd{}, "tui")
subcommands.Register(&commands.ScanCmd{}, "scan")
subcommands.Register(&commands.HistoryCmd{}, "history")
subcommands.Register(&commands.ReportCmd{}, "report")
subcommands.Register(&commands.ConfigtestCmd{}, "configtest")
subcommands.Register(&commands.ServerCmd{}, "server")
var v = flag.Bool("v", false, "Show version")
flag.Parse()
if *v {
fmt.Printf("vuls %s %s\n", config.Version, config.Revision)
os.Exit(int(subcommands.ExitSuccess))
}
ctx := context.Background()
os.Exit(int(subcommands.Execute(ctx)))
}

View File

@@ -1,360 +0,0 @@
package models
import (
"time"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
)
// CveContents has CveContent
type CveContents map[CveContentType]CveContent
// NewCveContents create CveContents
func NewCveContents(conts ...CveContent) CveContents {
m := CveContents{}
for _, cont := range conts {
m[cont.Type] = cont
}
return m
}
// CveContentStr has CveContentType and Value
type CveContentStr struct {
Type CveContentType
Value string
}
// Except returns CveContents except given keys for enumeration
func (v CveContents) Except(exceptCtypes ...CveContentType) (values CveContents) {
values = CveContents{}
for ctype, content := range v {
found := false
for _, exceptCtype := range exceptCtypes {
if ctype == exceptCtype {
found = true
break
}
}
if !found {
values[ctype] = content
}
}
return
}
// SourceLinks returns link of source
func (v CveContents) SourceLinks(lang, myFamily, cveID string) (values []CveContentStr) {
if lang == "ja" {
if cont, found := v[Jvn]; found && 0 < len(cont.SourceLink) {
values = append(values, CveContentStr{Jvn, cont.SourceLink})
}
}
order := CveContentTypes{Nvd, NvdXML, NewCveContentType(myFamily)}
for _, ctype := range order {
if cont, found := v[ctype]; found {
if cont.SourceLink == "" {
continue
}
values = append(values, CveContentStr{ctype, cont.SourceLink})
}
}
if len(values) == 0 {
return []CveContentStr{{
Type: Nvd,
Value: "https://nvd.nist.gov/vuln/detail/" + cveID,
}}
}
return values
}
/*
// Severities returns Severities
func (v CveContents) Severities(myFamily string) (values []CveContentStr) {
order := CveContentTypes{NVD, NewCveContentType(myFamily)}
order = append(order, AllCveContetTypes.Except(append(order)...)...)
for _, ctype := range order {
if cont, found := v[ctype]; found && 0 < len(cont.Severity) {
values = append(values, CveContentStr{
Type: ctype,
Value: cont.Severity,
})
}
}
return
}
*/
// CveContentCpes has CveContentType and Value
type CveContentCpes struct {
Type CveContentType
Value []Cpe
}
// Cpes returns affected CPEs of this Vulnerability
func (v CveContents) Cpes(myFamily string) (values []CveContentCpes) {
order := CveContentTypes{NewCveContentType(myFamily)}
order = append(order, AllCveContetTypes.Except(order...)...)
for _, ctype := range order {
if cont, found := v[ctype]; found && 0 < len(cont.Cpes) {
values = append(values, CveContentCpes{
Type: ctype,
Value: cont.Cpes,
})
}
}
return
}
// CveContentRefs has CveContentType and Cpes
type CveContentRefs struct {
Type CveContentType
Value []Reference
}
// References returns References
func (v CveContents) References(myFamily string) (values []CveContentRefs) {
order := CveContentTypes{NewCveContentType(myFamily)}
order = append(order, AllCveContetTypes.Except(order...)...)
for _, ctype := range order {
if cont, found := v[ctype]; found && 0 < len(cont.References) {
values = append(values, CveContentRefs{
Type: ctype,
Value: cont.References,
})
}
}
return
}
// CweIDs returns related CweIDs of the vulnerability
func (v CveContents) CweIDs(myFamily string) (values []CveContentStr) {
order := CveContentTypes{NewCveContentType(myFamily)}
order = append(order, AllCveContetTypes.Except(order...)...)
for _, ctype := range order {
if cont, found := v[ctype]; found && 0 < len(cont.CweIDs) {
for _, cweID := range cont.CweIDs {
for _, val := range values {
if val.Value == cweID {
continue
}
}
values = append(values, CveContentStr{
Type: ctype,
Value: cweID,
})
}
}
}
return
}
// UniqCweIDs returns Uniq CweIDs
func (v CveContents) UniqCweIDs(myFamily string) (values []CveContentStr) {
uniq := map[string]CveContentStr{}
for _, cwes := range v.CweIDs(myFamily) {
uniq[cwes.Value] = cwes
}
for _, cwe := range uniq {
values = append(values, cwe)
}
return values
}
// CveContent has abstraction of various vulnerability information
type CveContent struct {
Type CveContentType `json:"type"`
CveID string `json:"cveID"`
Title string `json:"title"`
Summary string `json:"summary"`
Cvss2Score float64 `json:"cvss2Score"`
Cvss2Vector string `json:"cvss2Vector"`
Cvss2Severity string `json:"cvss2Severity"`
Cvss3Score float64 `json:"cvss3Score"`
Cvss3Vector string `json:"cvss3Vector"`
Cvss3Severity string `json:"cvss3Severity"`
SourceLink string `json:"sourceLink"`
Cpes []Cpe `json:"cpes,omitempty"`
References References `json:"references,omitempty"`
CweIDs []string `json:"cweIDs,omitempty"`
Published time.Time `json:"published"`
LastModified time.Time `json:"lastModified"`
Mitigation string `json:"mitigation"` // RedHat API
Optional map[string]string `json:"optional,omitempty"`
}
// Empty checks the content is empty
func (c CveContent) Empty() bool {
return c.Summary == ""
}
// CveContentType is a source of CVE information
type CveContentType string
// NewCveContentType create CveContentType
func NewCveContentType(name string) CveContentType {
switch name {
case "nvdxml":
return NvdXML
case "nvd":
return Nvd
case "jvn":
return Jvn
case "redhat", "centos":
return RedHat
case "oracle":
return Oracle
case "ubuntu":
return Ubuntu
case "debian", vulnerability.DebianOVAL:
return Debian
case "redhat_api":
return RedHatAPI
case "debian_security_tracker":
return DebianSecurityTracker
case "microsoft":
return Microsoft
case "wordpress":
return WPVulnDB
case "amazon":
return Amazon
case "trivy":
return Trivy
// case vulnerability.NodejsSecurityWg:
// return NodeSec
// case vulnerability.PythonSafetyDB:
// return PythonSec
// case vulnerability.RustSec:
// return RustSec
// case vulnerability.PhpSecurityAdvisories:
// return PhpSec
// case vulnerability.RubySec:
// return RubySec
default:
return Unknown
}
}
const (
// NvdXML is NvdXML
NvdXML CveContentType = "nvdxml"
// Nvd is Nvd
Nvd CveContentType = "nvd"
// Jvn is Jvn
Jvn CveContentType = "jvn"
// RedHat is RedHat
RedHat CveContentType = "redhat"
// RedHatAPI is RedHat
RedHatAPI CveContentType = "redhat_api"
// DebianSecurityTracker is Debian Security tracker
DebianSecurityTracker CveContentType = "debian_security_tracker"
// Debian is Debian
Debian CveContentType = "debian"
// Ubuntu is Ubuntu
Ubuntu CveContentType = "ubuntu"
// Oracle is Oracle Linux
Oracle CveContentType = "oracle"
// Amazon is Amazon Linux
Amazon CveContentType = "amazon"
// SUSE is SUSE Linux
SUSE CveContentType = "suse"
// Microsoft is Microsoft
Microsoft CveContentType = "microsoft"
// WPVulnDB is WordPress
WPVulnDB CveContentType = "wpvulndb"
// Trivy is Trivy
Trivy CveContentType = "trivy"
// NodeSec : for JS
// NodeSec CveContentType = "node"
// // PythonSec : for PHP
// PythonSec CveContentType = "python"
// // PhpSec : for PHP
// PhpSec CveContentType = "php"
// // RubySec : for Ruby
// RubySec CveContentType = "ruby"
// // RustSec : for Rust
// RustSec CveContentType = "rust"
// Unknown is Unknown
Unknown CveContentType = "unknown"
)
// CveContentTypes has slide of CveContentType
type CveContentTypes []CveContentType
// AllCveContetTypes has all of CveContentTypes
var AllCveContetTypes = CveContentTypes{
Nvd,
NvdXML,
Jvn,
RedHat,
RedHatAPI,
Debian,
Ubuntu,
Amazon,
SUSE,
DebianSecurityTracker,
WPVulnDB,
Trivy,
// NodeSec,
// PythonSec,
// PhpSec,
// RubySec,
// RustSec,
}
// Except returns CveContentTypes except for given args
func (c CveContentTypes) Except(excepts ...CveContentType) (excepted CveContentTypes) {
for _, ctype := range c {
found := false
for _, except := range excepts {
if ctype == except {
found = true
break
}
}
if !found {
excepted = append(excepted, ctype)
}
}
return
}
// Cpe is Common Platform Enumeration
type Cpe struct {
URI string `json:"uri"`
FormattedString string `json:"formattedString"`
}
// References is a slice of Reference
type References []Reference
// Reference has a related link of the CVE
type Reference struct {
Source string `json:"source"`
Link string `json:"link"`
RefID string `json:"refID"`
}

View File

@@ -1,190 +0,0 @@
package models
import (
"reflect"
"testing"
)
func TestExcept(t *testing.T) {
var tests = []struct {
in CveContents
out CveContents
}{{
in: CveContents{
RedHat: {Type: RedHat},
Ubuntu: {Type: Ubuntu},
Debian: {Type: Debian},
},
out: CveContents{
RedHat: {Type: RedHat},
},
},
}
for _, tt := range tests {
actual := tt.in.Except(Ubuntu, Debian)
if !reflect.DeepEqual(tt.out, actual) {
t.Errorf("\nexpected: %v\n actual: %v\n", tt.out, actual)
}
}
}
func TestSourceLinks(t *testing.T) {
type in struct {
lang string
cveID string
cont CveContents
}
var tests = []struct {
in in
out []CveContentStr
}{
// lang: ja
{
in: in{
lang: "ja",
cveID: "CVE-2017-6074",
cont: CveContents{
Jvn: {
Type: Jvn,
SourceLink: "https://jvn.jp/vu/JVNVU93610402/",
},
RedHat: {
Type: RedHat,
SourceLink: "https://access.redhat.com/security/cve/CVE-2017-6074",
},
NvdXML: {
Type: NvdXML,
SourceLink: "https://nvd.nist.gov/vuln/detail/CVE-2017-6074",
},
},
},
out: []CveContentStr{
{
Type: Jvn,
Value: "https://jvn.jp/vu/JVNVU93610402/",
},
{
Type: NvdXML,
Value: "https://nvd.nist.gov/vuln/detail/CVE-2017-6074",
},
{
Type: RedHat,
Value: "https://access.redhat.com/security/cve/CVE-2017-6074",
},
},
},
// lang: en
{
in: in{
lang: "en",
cveID: "CVE-2017-6074",
cont: CveContents{
Jvn: {
Type: Jvn,
SourceLink: "https://jvn.jp/vu/JVNVU93610402/",
},
RedHat: {
Type: RedHat,
SourceLink: "https://access.redhat.com/security/cve/CVE-2017-6074",
},
NvdXML: {
Type: NvdXML,
SourceLink: "https://nvd.nist.gov/vuln/detail/CVE-2017-6074",
},
},
},
out: []CveContentStr{
{
Type: NvdXML,
Value: "https://nvd.nist.gov/vuln/detail/CVE-2017-6074",
},
{
Type: RedHat,
Value: "https://access.redhat.com/security/cve/CVE-2017-6074",
},
},
},
// lang: empty
{
in: in{
lang: "en",
cveID: "CVE-2017-6074",
cont: CveContents{},
},
out: []CveContentStr{
{
Type: Nvd,
Value: "https://nvd.nist.gov/vuln/detail/CVE-2017-6074",
},
},
},
}
for i, tt := range tests {
actual := tt.in.cont.SourceLinks(tt.in.lang, "redhat", tt.in.cveID)
if !reflect.DeepEqual(tt.out, actual) {
t.Errorf("\n[%d] expected: %v\n actual: %v\n", i, tt.out, actual)
}
}
}
func TestVendorLink(t *testing.T) {
type in struct {
family string
vinfo VulnInfo
}
var tests = []struct {
in in
out map[string]string
}{
{
in: in{
family: "redhat",
vinfo: VulnInfo{
CveID: "CVE-2017-6074",
CveContents: CveContents{
Jvn: {
Type: Jvn,
SourceLink: "https://jvn.jp/vu/JVNVU93610402/",
},
RedHat: {
Type: RedHat,
SourceLink: "https://access.redhat.com/security/cve/CVE-2017-6074",
},
NvdXML: {
Type: NvdXML,
SourceLink: "https://nvd.nist.gov/vuln/detail/CVE-2017-6074",
},
},
},
},
out: map[string]string{
"RHEL-CVE": "https://access.redhat.com/security/cve/CVE-2017-6074",
},
},
{
in: in{
family: "ubuntu",
vinfo: VulnInfo{
CveID: "CVE-2017-6074",
CveContents: CveContents{
RedHat: {
Type: Ubuntu,
SourceLink: "https://access.redhat.com/security/cve/CVE-2017-6074",
},
},
},
},
out: map[string]string{
"Ubuntu-CVE": "http://people.ubuntu.com/~ubuntu-security/cve/CVE-2017-6074",
},
},
}
for _, tt := range tests {
actual := tt.in.vinfo.VendorLinks(tt.in.family)
for k := range tt.out {
if tt.out[k] != actual[k] {
t.Errorf("\nexpected: %s\n actual: %s\n", tt.out[k], actual[k])
}
}
}
}

View File

@@ -1,145 +0,0 @@
package models
import (
"path/filepath"
"github.com/aquasecurity/trivy-db/pkg/db"
trivyDBTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/detector/library"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/future-architect/vuls/util"
"golang.org/x/xerrors"
// "github.com/aquasecurity/go-dep-parser/pkg/types"
"github.com/knqyf263/go-version"
)
// LibraryScanners is an array of LibraryScanner
type LibraryScanners []LibraryScanner
// Find : find by name
func (lss LibraryScanners) Find(path, name string) map[string]types.Library {
filtered := map[string]types.Library{}
for _, ls := range lss {
for _, lib := range ls.Libs {
if ls.Path == path && lib.Name == name {
filtered[ls.Path] = lib
break
}
}
}
return filtered
}
// LibraryScanner has libraries information
type LibraryScanner struct {
Path string
Libs []types.Library
}
// Scan : scan target library
func (s LibraryScanner) Scan() ([]VulnInfo, error) {
scanner, err := library.DriverFactory{}.NewDriver(filepath.Base(string(s.Path)))
if err != nil {
return nil, xerrors.Errorf("Failed to new a library driver: %w", err)
}
var vulnerabilities = []VulnInfo{}
for _, pkg := range s.Libs {
v, err := version.NewVersion(pkg.Version)
if err != nil {
util.Log.Debugf("new version cant detected %s@%s", pkg.Name, pkg.Version)
continue
}
tvulns, err := scanner.Detect(pkg.Name, v)
if err != nil {
return nil, xerrors.Errorf("failed to detect %s vulnerabilities: %w", scanner.Type(), err)
}
if len(tvulns) == 0 {
continue
}
vulns := s.convertFanalToVuln(tvulns)
vulnerabilities = append(vulnerabilities, vulns...)
}
return vulnerabilities, nil
}
func (s LibraryScanner) convertFanalToVuln(tvulns []types.DetectedVulnerability) (vulns []VulnInfo) {
for _, tvuln := range tvulns {
vinfo, err := s.getVulnDetail(tvuln)
if err != nil {
util.Log.Debugf("failed to getVulnDetail. err: %s, tvuln: %#v", err, tvuln)
continue
}
vulns = append(vulns, vinfo)
}
return vulns
}
func (s LibraryScanner) getVulnDetail(tvuln types.DetectedVulnerability) (vinfo VulnInfo, err error) {
vul, err := db.Config{}.GetVulnerability(tvuln.VulnerabilityID)
if err != nil {
return vinfo, err
}
vinfo.CveID = tvuln.VulnerabilityID
vinfo.CveContents = getCveContents(tvuln.VulnerabilityID, vul)
if tvuln.FixedVersion != "" {
vinfo.LibraryFixedIns = []LibraryFixedIn{
{
Key: s.GetLibraryKey(),
Name: tvuln.PkgName,
FixedIn: tvuln.FixedVersion,
Path: s.Path,
},
}
}
return vinfo, nil
}
func getCveContents(cveID string, vul trivyDBTypes.Vulnerability) (contents map[CveContentType]CveContent) {
contents = map[CveContentType]CveContent{}
refs := []Reference{}
for _, refURL := range vul.References {
refs = append(refs, Reference{Source: "trivy", Link: refURL})
}
content := CveContent{
Type: Trivy,
CveID: cveID,
Title: vul.Title,
Summary: vul.Description,
Cvss3Severity: string(vul.Severity),
References: refs,
}
contents[Trivy] = content
return contents
}
// LibraryMap is filename and library type
var LibraryMap = map[string]string{
"package-lock.json": "node",
"yarn.lock": "node",
"Gemfile.lock": "ruby",
"Cargo.lock": "rust",
"composer.lock": "php",
"Pipfile.lock": "python",
"poetry.lock": "python",
}
// GetLibraryKey returns target library key
func (s LibraryScanner) GetLibraryKey() string {
fileName := filepath.Base(s.Path)
return LibraryMap[fileName]
}
// LibraryFixedIn has library fixed information
type LibraryFixedIn struct {
Key string `json:"key,omitempty"`
Name string `json:"name,omitempty"`
FixedIn string `json:"fixedIn,omitempty"`
Path string `json:"path,omitempty"`
}

View File

@@ -1,96 +0,0 @@
package models
import (
"reflect"
"testing"
"github.com/aquasecurity/trivy/pkg/types"
)
func TestLibraryScanners_Find(t *testing.T) {
type args struct {
path string
name string
}
tests := []struct {
name string
lss LibraryScanners
args args
want map[string]types.Library
}{
{
name: "single file",
lss: LibraryScanners{
{
Path: "/pathA",
Libs: []types.Library{
{
Name: "libA",
Version: "1.0.0",
},
},
},
},
args: args{"/pathA", "libA"},
want: map[string]types.Library{
"/pathA": {
Name: "libA",
Version: "1.0.0",
},
},
},
{
name: "multi file",
lss: LibraryScanners{
{
Path: "/pathA",
Libs: []types.Library{
{
Name: "libA",
Version: "1.0.0",
},
},
},
{
Path: "/pathB",
Libs: []types.Library{
{
Name: "libA",
Version: "1.0.5",
},
},
},
},
args: args{"/pathA", "libA"},
want: map[string]types.Library{
"/pathA": {
Name: "libA",
Version: "1.0.0",
},
},
},
{
name: "miss",
lss: LibraryScanners{
{
Path: "/pathA",
Libs: []types.Library{
{
Name: "libA",
Version: "1.0.0",
},
},
},
},
args: args{"/pathA", "libB"},
want: map[string]types.Library{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.lss.Find(tt.args.path, tt.args.name); !reflect.DeepEqual(got, tt.want) {
t.Errorf("LibraryScanners.Find() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -1,4 +0,0 @@
package models
// JSONVersion is JSON Version
const JSONVersion = 4

View File

@@ -1,255 +0,0 @@
package models
import (
"bytes"
"fmt"
"regexp"
"strings"
"golang.org/x/xerrors"
)
// Packages is Map of Package
// { "package-name": Package }
type Packages map[string]Package
// NewPackages create Packages
func NewPackages(packs ...Package) Packages {
m := Packages{}
for _, pack := range packs {
m[pack.Name] = pack
}
return m
}
// MergeNewVersion merges candidate version information to the receiver struct
func (ps Packages) MergeNewVersion(as Packages) {
for name, pack := range ps {
pack.NewVersion = pack.Version
pack.NewRelease = pack.Release
ps[name] = pack
}
for _, a := range as {
if pack, ok := ps[a.Name]; ok {
pack.NewVersion = a.NewVersion
pack.NewRelease = a.NewRelease
pack.Repository = a.Repository
ps[a.Name] = pack
}
}
}
// Merge returns merged map (immutable)
func (ps Packages) Merge(other Packages) Packages {
merged := Packages{}
for k, v := range ps {
merged[k] = v
}
for k, v := range other {
merged[k] = v
}
return merged
}
// FindOne search a element
func (ps Packages) FindOne(f func(Package) bool) (string, Package, bool) {
for key, p := range ps {
if f(p) {
return key, p, true
}
}
return "", Package{}, false
}
// FindByFQPN search a package by Fully-Qualified-Package-Name
func (ps Packages) FindByFQPN(nameVerRelArc string) (*Package, error) {
for _, p := range ps {
if nameVerRelArc == p.FQPN() {
return &p, nil
}
}
return nil, xerrors.Errorf("Failed to find the package: %s", nameVerRelArc)
}
// Package has installed binary packages.
type Package struct {
Name string `json:"name"`
Version string `json:"version"`
Release string `json:"release"`
NewVersion string `json:"newVersion"`
NewRelease string `json:"newRelease"`
Arch string `json:"arch"`
Repository string `json:"repository"`
Changelog Changelog `json:"changelog"`
AffectedProcs []AffectedProcess `json:",omitempty"`
NeedRestartProcs []NeedRestartProcess `json:",omitempty"`
}
// FQPN returns Fully-Qualified-Package-Name
// name-version-release.arch
func (p Package) FQPN() string {
fqpn := p.Name
if p.Version != "" {
fqpn += fmt.Sprintf("-%s", p.Version)
}
if p.Release != "" {
fqpn += fmt.Sprintf("-%s", p.Release)
}
if p.Arch != "" {
fqpn += fmt.Sprintf(".%s", p.Arch)
}
return fqpn
}
// FormatVer returns package version-release
func (p Package) FormatVer() string {
ver := p.Version
if 0 < len(p.Release) {
ver = fmt.Sprintf("%s-%s", ver, p.Release)
}
return ver
}
// FormatNewVer returns package version-release
func (p Package) FormatNewVer() string {
ver := p.NewVersion
if 0 < len(p.NewRelease) {
ver = fmt.Sprintf("%s-%s", ver, p.NewRelease)
}
return ver
}
// FormatVersionFromTo formats installed and new package version
func (p Package) FormatVersionFromTo(stat PackageFixStatus) string {
to := p.FormatNewVer()
if stat.NotFixedYet {
if stat.FixState != "" {
to = stat.FixState
} else {
to = "Not Fixed Yet"
}
} else if p.NewVersion == "" {
to = "Unknown"
}
var fixedIn string
if stat.FixedIn != "" {
fixedIn = fmt.Sprintf(" (FixedIn: %s)", stat.FixedIn)
}
return fmt.Sprintf("%s-%s -> %s%s",
p.Name, p.FormatVer(), to, fixedIn)
}
// FormatChangelog formats the changelog
func (p Package) FormatChangelog() string {
buf := []string{}
packVer := fmt.Sprintf("%s-%s -> %s",
p.Name, p.FormatVer(), p.FormatNewVer())
var delim bytes.Buffer
for i := 0; i < len(packVer); i++ {
delim.WriteString("-")
}
clog := p.Changelog.Contents
if lines := strings.Split(clog, "\n"); len(lines) != 0 {
clog = strings.Join(lines[0:len(lines)-1], "\n")
}
switch p.Changelog.Method {
case FailedToGetChangelog:
clog = "No changelogs"
case FailedToFindVersionInChangelog:
clog = "Failed to parse changelogs. For details, check yourself"
}
buf = append(buf, packVer, delim.String(), clog)
return strings.Join(buf, "\n")
}
// Changelog has contents of changelog and how to get it.
// Method: models.detectionMethodStr
type Changelog struct {
Contents string `json:"contents"`
Method DetectionMethod `json:"method"`
}
// AffectedProcess keep a processes information affected by software update
type AffectedProcess struct {
PID string `json:"pid,omitempty"`
Name string `json:"name,omitempty"`
ListenPorts []string `json:"listenPorts,omitempty"`
}
// NeedRestartProcess keep a processes information affected by software update
type NeedRestartProcess struct {
PID string `json:"pid"`
Path string `json:"path"`
ServiceName string `json:"serviceName"`
InitSystem string `json:"initSystem"`
HasInit bool `json:"-"`
}
// SrcPackage has installed source package information.
// Debian based Linux has both of package and source information in dpkg.
// OVAL database often includes a source version (Not a binary version),
// so it is also needed to capture source version for OVAL version comparison.
// https://github.com/future-architect/vuls/issues/504
type SrcPackage struct {
Name string `json:"name"`
Version string `json:"version"`
Arch string `json:"arch"`
BinaryNames []string `json:"binaryNames"`
}
// AddBinaryName add the name if not exists
func (s *SrcPackage) AddBinaryName(name string) {
found := false
for _, n := range s.BinaryNames {
if n == name {
return
}
}
if !found {
s.BinaryNames = append(s.BinaryNames, name)
}
}
// SrcPackages is Map of SrcPackage
// { "package-name": SrcPackage }
type SrcPackages map[string]SrcPackage
// FindByBinName finds by bin-package-name
func (s SrcPackages) FindByBinName(name string) (*SrcPackage, bool) {
for _, p := range s {
for _, binName := range p.BinaryNames {
if binName == name {
return &p, true
}
}
}
return nil, false
}
// raspiPackNamePattern is a regular expression pattern to detect the Raspberry Pi specific package from the package name.
// e.g. libraspberrypi-dev, rpi-eeprom, python3-rpi.gpio, pi-bluetooth
var raspiPackNamePattern = regexp.MustCompile(`(.*raspberry.*|^rpi.*|.*-rpi.*|^pi-.*)`)
// raspiPackNamePattern is a regular expression pattern to detect the Raspberry Pi specific package from the version.
// e.g. ffmpeg 7:4.1.4-1+rpt7~deb10u1, vlc 3.0.10-0+deb10u1+rpt2
var raspiPackVersionPattern = regexp.MustCompile(`.+\+rp(t|i)\d+`)
// raspiPackNameList is a package name array of Raspberry Pi specific packages that are difficult to detect with regular expressions.
var raspiPackNameList = []string{"piclone", "pipanel", "pishutdown", "piwiz", "pixflat-icons"}
// IsRaspbianPackage judges whether it is a package related to Raspberry Pi from the package name and version
func IsRaspbianPackage(name, version string) bool {
if raspiPackNamePattern.MatchString(name) || raspiPackVersionPattern.MatchString(version) {
return true
}
for _, n := range raspiPackNameList {
if n == name {
return true
}
}
return false
}

View File

@@ -1,383 +0,0 @@
package models
import (
"reflect"
"testing"
"github.com/k0kubun/pp"
)
func TestMergeNewVersion(t *testing.T) {
var test = struct {
a Packages
b Packages
expected Packages
}{
Packages{
"hoge": {
Name: "hoge",
},
},
Packages{
"hoge": {
Name: "hoge",
NewVersion: "1.0.0",
NewRelease: "release1",
},
},
Packages{
"hoge": {
Name: "hoge",
NewVersion: "1.0.0",
NewRelease: "release1",
},
},
}
test.a.MergeNewVersion(test.b)
if !reflect.DeepEqual(test.a, test.expected) {
e := pp.Sprintf("%v", test.a)
a := pp.Sprintf("%v", test.expected)
t.Errorf("expected %s, actual %s", e, a)
}
}
func TestMerge(t *testing.T) {
var test = struct {
a Packages
b Packages
expected Packages
}{
Packages{
"hoge": {Name: "hoge"},
"fuga": {Name: "fuga"},
},
Packages{
"hega": {Name: "hega"},
"hage": {Name: "hage"},
},
Packages{
"hoge": {Name: "hoge"},
"fuga": {Name: "fuga"},
"hega": {Name: "hega"},
"hage": {Name: "hage"},
},
}
actual := test.a.Merge(test.b)
if !reflect.DeepEqual(actual, test.expected) {
e := pp.Sprintf("%v", test.expected)
a := pp.Sprintf("%v", actual)
t.Errorf("expected %s, actual %s", e, a)
}
}
func TestAddBinaryName(t *testing.T) {
var tests = []struct {
in SrcPackage
name string
expected SrcPackage
}{
{
SrcPackage{Name: "hoge"},
"curl",
SrcPackage{
Name: "hoge",
BinaryNames: []string{"curl"},
},
},
{
SrcPackage{
Name: "hoge",
BinaryNames: []string{"curl"},
},
"curl",
SrcPackage{
Name: "hoge",
BinaryNames: []string{"curl"},
},
},
{
SrcPackage{
Name: "hoge",
BinaryNames: []string{"curl"},
},
"openssh",
SrcPackage{
Name: "hoge",
BinaryNames: []string{"curl", "openssh"},
},
},
}
for _, tt := range tests {
tt.in.AddBinaryName(tt.name)
if !reflect.DeepEqual(tt.in, tt.expected) {
t.Errorf("expected %#v, actual %#v", tt.in, tt.expected)
}
}
}
func TestFindByBinName(t *testing.T) {
var tests = []struct {
in SrcPackages
name string
expected *SrcPackage
ok bool
}{
{
in: map[string]SrcPackage{
"packA": {
Name: "srcA",
BinaryNames: []string{"binA"},
Version: "1.0.0",
},
"packB": {
Name: "srcB",
BinaryNames: []string{"binB"},
Version: "2.0.0",
},
},
name: "binA",
expected: &SrcPackage{
Name: "srcA",
BinaryNames: []string{"binA"},
Version: "1.0.0",
},
ok: true,
},
{
in: map[string]SrcPackage{
"packA": {
Name: "srcA",
BinaryNames: []string{"binA"},
Version: "1.0.0",
},
"packB": {
Name: "srcB",
BinaryNames: []string{"binB"},
Version: "2.0.0",
},
},
name: "nobin",
expected: nil,
ok: false,
},
}
for i, tt := range tests {
act, ok := tt.in.FindByBinName(tt.name)
if ok != tt.ok {
t.Errorf("[%d] expected %#v, actual %#v", i, tt.in, tt.expected)
}
if act != nil && !reflect.DeepEqual(*tt.expected, *act) {
t.Errorf("[%d] expected %#v, actual %#v", i, tt.in, tt.expected)
}
}
}
func TestPackage_FormatVersionFromTo(t *testing.T) {
type fields struct {
Name string
Version string
Release string
NewVersion string
NewRelease string
Arch string
Repository string
Changelog Changelog
AffectedProcs []AffectedProcess
NeedRestartProcs []NeedRestartProcess
}
type args struct {
stat PackageFixStatus
}
tests := []struct {
name string
fields fields
args args
want string
}{
{
name: "fixed",
fields: fields{
Name: "packA",
Version: "1.0.0",
Release: "a",
NewVersion: "1.0.1",
NewRelease: "b",
},
args: args{
stat: PackageFixStatus{
NotFixedYet: false,
FixedIn: "1.0.1-b",
},
},
want: "packA-1.0.0-a -> 1.0.1-b (FixedIn: 1.0.1-b)",
},
{
name: "nfy",
fields: fields{
Name: "packA",
Version: "1.0.0",
Release: "a",
},
args: args{
stat: PackageFixStatus{
NotFixedYet: true,
},
},
want: "packA-1.0.0-a -> Not Fixed Yet",
},
{
name: "nfy",
fields: fields{
Name: "packA",
Version: "1.0.0",
Release: "a",
},
args: args{
stat: PackageFixStatus{
NotFixedYet: false,
FixedIn: "1.0.1-b",
},
},
want: "packA-1.0.0-a -> Unknown (FixedIn: 1.0.1-b)",
},
{
name: "nfy2",
fields: fields{
Name: "packA",
Version: "1.0.0",
Release: "a",
},
args: args{
stat: PackageFixStatus{
NotFixedYet: true,
FixedIn: "1.0.1-b",
FixState: "open",
},
},
want: "packA-1.0.0-a -> open (FixedIn: 1.0.1-b)",
},
{
name: "nfy3",
fields: fields{
Name: "packA",
Version: "1.0.0",
Release: "a",
},
args: args{
stat: PackageFixStatus{
NotFixedYet: true,
FixedIn: "1.0.1-b",
FixState: "open",
},
},
want: "packA-1.0.0-a -> open (FixedIn: 1.0.1-b)",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := Package{
Name: tt.fields.Name,
Version: tt.fields.Version,
Release: tt.fields.Release,
NewVersion: tt.fields.NewVersion,
NewRelease: tt.fields.NewRelease,
Arch: tt.fields.Arch,
Repository: tt.fields.Repository,
Changelog: tt.fields.Changelog,
AffectedProcs: tt.fields.AffectedProcs,
NeedRestartProcs: tt.fields.NeedRestartProcs,
}
if got := p.FormatVersionFromTo(tt.args.stat); got != tt.want {
t.Errorf("Package.FormatVersionFromTo() = %v, want %v", got, tt.want)
}
})
}
}
func Test_IsRaspbianPackage(t *testing.T) {
type args struct {
name string
ver string
}
tests := []struct {
name string
in []args
expect []bool
}{
{
name: "nameRegExp",
in: []args{
{
name: "libraspberrypi-dev",
ver: "1.20200811-1",
},
{
name: "rpi-eeprom",
ver: "7.10-1",
},
{
name: "python3-rpi.gpio",
ver: "0.7.0-0.1~bpo10+1",
},
{
name: "arping",
ver: "2.19-6",
},
{
name: "pi-bluetooth",
ver: "0.1.14",
},
},
expect: []bool{true, true, true, false, true, false},
},
{
name: "verRegExp",
in: []args{
{
name: "ffmpeg",
ver: "7:4.1.6-1~deb10u1+rpt1",
},
{
name: "gcc",
ver: "4:8.3.0-1+rpi2",
},
},
expect: []bool{true, true},
},
{
name: "nameList",
in: []args{
{
name: "piclone",
ver: "0.16",
},
},
expect: []bool{true},
},
{
name: "debianPackage",
in: []args{
{
name: "apt",
ver: "1.8.2.1",
},
},
expect: []bool{false},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
for i, p := range tt.in {
ret := IsRaspbianPackage(p.name, p.ver)
if !reflect.DeepEqual(ret, tt.expect[i]) {
t.Errorf("[%s->%s] expected: %t, actual: %t, in: %#v", tt.name, tt.in[i].name, tt.expect[i], ret, tt.in[i])
}
}
})
}
}

View File

@@ -1,501 +0,0 @@
package models
import (
"bytes"
"fmt"
"regexp"
"strings"
"time"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/cwe"
"github.com/future-architect/vuls/util"
)
// ScanResults is a slide of ScanResult
type ScanResults []ScanResult
// ScanResult has the result of scanned CVE information.
type ScanResult struct {
JSONVersion int `json:"jsonVersion"`
Lang string `json:"lang"`
ServerUUID string `json:"serverUUID"`
ServerName string `json:"serverName"` // TOML Section key
Family string `json:"family"`
Release string `json:"release"`
Container Container `json:"container"`
Platform Platform `json:"platform"`
IPv4Addrs []string `json:"ipv4Addrs,omitempty"` // only global unicast address (https://golang.org/pkg/net/#IP.IsGlobalUnicast)
IPv6Addrs []string `json:"ipv6Addrs,omitempty"` // only global unicast address (https://golang.org/pkg/net/#IP.IsGlobalUnicast)
IPSIdentifiers map[config.IPS]string `json:"ipsIdentifiers,omitempty"`
ScannedAt time.Time `json:"scannedAt"`
ScanMode string `json:"scanMode"`
ScannedVersion string `json:"scannedVersion"`
ScannedRevision string `json:"scannedRevision"`
ScannedBy string `json:"scannedBy"`
ScannedVia string `json:"scannedVia"`
ScannedIPv4Addrs []string `json:"scannedIpv4Addrs,omitempty"`
ScannedIPv6Addrs []string `json:"scannedIpv6Addrs,omitempty"`
ReportedAt time.Time `json:"reportedAt"`
ReportedVersion string `json:"reportedVersion"`
ReportedRevision string `json:"reportedRevision"`
ReportedBy string `json:"reportedBy"`
Errors []string `json:"errors"`
Warnings []string `json:"warnings"`
ScannedCves VulnInfos `json:"scannedCves"`
RunningKernel Kernel `json:"runningKernel"`
Packages Packages `json:"packages"`
SrcPackages SrcPackages `json:",omitempty"`
WordPressPackages *WordPressPackages `json:",omitempty"`
LibraryScanners LibraryScanners `json:"libraries,omitempty"`
CweDict CweDict `json:"cweDict,omitempty"`
Optional map[string]interface{} `json:",omitempty"`
Config struct {
Scan config.Config `json:"scan"`
Report config.Config `json:"report"`
} `json:"config"`
}
// CweDict is a dictionary for CWE
type CweDict map[string]CweDictEntry
// Get the name, url, top10URL for the specified cweID, lang
func (c CweDict) Get(cweID, lang string) (name, url, top10Rank, top10URL, cweTop25Rank, cweTop25URL, sansTop25Rank, sansTop25URL string) {
cweNum := strings.TrimPrefix(cweID, "CWE-")
switch config.Conf.Lang {
case "ja":
if dict, ok := c[cweNum]; ok && dict.OwaspTopTen2017 != "" {
top10Rank = dict.OwaspTopTen2017
top10URL = cwe.OwaspTopTen2017GitHubURLJa[dict.OwaspTopTen2017]
}
if dict, ok := c[cweNum]; ok && dict.CweTopTwentyfive2019 != "" {
cweTop25Rank = dict.CweTopTwentyfive2019
cweTop25URL = cwe.CweTopTwentyfive2019URL
}
if dict, ok := c[cweNum]; ok && dict.SansTopTwentyfive != "" {
sansTop25Rank = dict.SansTopTwentyfive
sansTop25URL = cwe.SansTopTwentyfiveURL
}
if dict, ok := cwe.CweDictJa[cweNum]; ok {
name = dict.Name
url = fmt.Sprintf("http://jvndb.jvn.jp/ja/cwe/%s.html", cweID)
} else {
if dict, ok := cwe.CweDictEn[cweNum]; ok {
name = dict.Name
}
url = fmt.Sprintf("https://cwe.mitre.org/data/definitions/%s.html", cweID)
}
default:
if dict, ok := c[cweNum]; ok && dict.OwaspTopTen2017 != "" {
top10Rank = dict.OwaspTopTen2017
top10URL = cwe.OwaspTopTen2017GitHubURLEn[dict.OwaspTopTen2017]
}
if dict, ok := c[cweNum]; ok && dict.CweTopTwentyfive2019 != "" {
cweTop25Rank = dict.CweTopTwentyfive2019
cweTop25URL = cwe.CweTopTwentyfive2019URL
}
if dict, ok := c[cweNum]; ok && dict.SansTopTwentyfive != "" {
sansTop25Rank = dict.SansTopTwentyfive
sansTop25URL = cwe.SansTopTwentyfiveURL
}
url = fmt.Sprintf("https://cwe.mitre.org/data/definitions/%s.html", cweID)
if dict, ok := cwe.CweDictEn[cweNum]; ok {
name = dict.Name
}
}
return
}
// CweDictEntry is a entry of CWE
type CweDictEntry struct {
En *cwe.Cwe `json:"en,omitempty"`
Ja *cwe.Cwe `json:"ja,omitempty"`
OwaspTopTen2017 string `json:"owaspTopTen2017"`
CweTopTwentyfive2019 string `json:"cweTopTwentyfive2019"`
SansTopTwentyfive string `json:"sansTopTwentyfive"`
}
// Kernel has the Release, version and whether need restart
type Kernel struct {
Release string `json:"release"`
Version string `json:"version"`
RebootRequired bool `json:"rebootRequired"`
}
// FilterByCvssOver is filter function.
func (r ScanResult) FilterByCvssOver(over float64) ScanResult {
filtered := r.ScannedCves.Find(func(v VulnInfo) bool {
v2Max := v.MaxCvss2Score()
v3Max := v.MaxCvss3Score()
max := v2Max.Value.Score
if max < v3Max.Value.Score {
max = v3Max.Value.Score
}
if over <= max {
return true
}
return false
})
r.ScannedCves = filtered
return r
}
// FilterIgnoreCves is filter function.
func (r ScanResult) FilterIgnoreCves() ScanResult {
ignoreCves := []string{}
if len(r.Container.Name) == 0 {
ignoreCves = config.Conf.Servers[r.ServerName].IgnoreCves
} else {
if s, ok := config.Conf.Servers[r.ServerName]; ok {
if con, ok := s.Containers[r.Container.Name]; ok {
ignoreCves = con.IgnoreCves
} else {
return r
}
} else {
util.Log.Errorf("%s is not found in config.toml",
r.ServerName)
return r
}
}
filtered := r.ScannedCves.Find(func(v VulnInfo) bool {
for _, c := range ignoreCves {
if v.CveID == c {
return false
}
}
return true
})
r.ScannedCves = filtered
return r
}
// FilterUnfixed is filter function.
func (r ScanResult) FilterUnfixed() ScanResult {
if !config.Conf.IgnoreUnfixed {
return r
}
filtered := r.ScannedCves.Find(func(v VulnInfo) bool {
// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'
if len(v.CpeURIs) != 0 {
return true
}
NotFixedAll := true
for _, p := range v.AffectedPackages {
NotFixedAll = NotFixedAll && p.NotFixedYet
}
return !NotFixedAll
})
r.ScannedCves = filtered
return r
}
// FilterIgnorePkgs is filter function.
func (r ScanResult) FilterIgnorePkgs() ScanResult {
var ignorePkgsRegexps []string
if len(r.Container.Name) == 0 {
ignorePkgsRegexps = config.Conf.Servers[r.ServerName].IgnorePkgsRegexp
} else {
if s, ok := config.Conf.Servers[r.ServerName]; ok {
if con, ok := s.Containers[r.Container.Name]; ok {
ignorePkgsRegexps = con.IgnorePkgsRegexp
} else {
return r
}
} else {
util.Log.Errorf("%s is not found in config.toml",
r.ServerName)
return r
}
}
regexps := []*regexp.Regexp{}
for _, pkgRegexp := range ignorePkgsRegexps {
re, err := regexp.Compile(pkgRegexp)
if err != nil {
util.Log.Errorf("Failed to parse %s. err: %+v", pkgRegexp, err)
continue
} else {
regexps = append(regexps, re)
}
}
if len(regexps) == 0 {
return r
}
filtered := r.ScannedCves.Find(func(v VulnInfo) bool {
if len(v.AffectedPackages) == 0 {
return true
}
for _, p := range v.AffectedPackages {
match := false
for _, re := range regexps {
if re.MatchString(p.Name) {
match = true
}
}
if !match {
return true
}
}
return false
})
r.ScannedCves = filtered
return r
}
// FilterInactiveWordPressLibs is filter function.
func (r ScanResult) FilterInactiveWordPressLibs() ScanResult {
if !config.Conf.Servers[r.ServerName].WordPress.IgnoreInactive {
return r
}
filtered := r.ScannedCves.Find(func(v VulnInfo) bool {
if len(v.WpPackageFixStats) == 0 {
return true
}
// Ignore if all libs in this vulnInfo inactive
for _, wp := range v.WpPackageFixStats {
if p, ok := r.WordPressPackages.Find(wp.Name); ok {
if p.Status != Inactive {
return true
}
}
}
return false
})
r.ScannedCves = filtered
return r
}
// ReportFileName returns the filename on localhost without extension
func (r ScanResult) ReportFileName() (name string) {
if len(r.Container.ContainerID) == 0 {
return fmt.Sprintf("%s", r.ServerName)
}
return fmt.Sprintf("%s@%s", r.Container.Name, r.ServerName)
}
// ReportKeyName returns the name of key on S3, Azure-Blob without extension
func (r ScanResult) ReportKeyName() (name string) {
timestr := r.ScannedAt.Format(time.RFC3339)
if len(r.Container.ContainerID) == 0 {
return fmt.Sprintf("%s/%s", timestr, r.ServerName)
}
return fmt.Sprintf("%s/%s@%s", timestr, r.Container.Name, r.ServerName)
}
// ServerInfo returns server name one line
func (r ScanResult) ServerInfo() string {
if len(r.Container.ContainerID) == 0 {
return fmt.Sprintf("%s (%s%s)",
r.FormatServerName(), r.Family, r.Release)
}
return fmt.Sprintf(
"%s (%s%s) on %s",
r.FormatServerName(),
r.Family,
r.Release,
r.ServerName,
)
}
// ServerInfoTui returns server information for TUI sidebar
func (r ScanResult) ServerInfoTui() string {
if len(r.Container.ContainerID) == 0 {
line := fmt.Sprintf("%s (%s%s)",
r.ServerName, r.Family, r.Release)
if len(r.Warnings) != 0 {
line = "[Warn] " + line
}
if r.RunningKernel.RebootRequired {
return "[Reboot] " + line
}
return line
}
fmtstr := "|-- %s (%s%s)"
if r.RunningKernel.RebootRequired {
fmtstr = "|-- [Reboot] %s (%s%s)"
}
return fmt.Sprintf(fmtstr, r.Container.Name, r.Family, r.Release)
}
// FormatServerName returns server and container name
func (r ScanResult) FormatServerName() (name string) {
if len(r.Container.ContainerID) == 0 {
name = r.ServerName
} else {
name = fmt.Sprintf("%s@%s",
r.Container.Name, r.ServerName)
}
if r.RunningKernel.RebootRequired {
name = "[Reboot Required] " + name
}
return
}
// FormatTextReportHeader returns header of text report
func (r ScanResult) FormatTextReportHeader() string {
var buf bytes.Buffer
for i := 0; i < len(r.ServerInfo()); i++ {
buf.WriteString("=")
}
return fmt.Sprintf("%s\n%s\n%s, %s, %s, %s, %s, %s\n",
r.ServerInfo(),
buf.String(),
r.ScannedCves.FormatCveSummary(),
r.ScannedCves.FormatFixedStatus(r.Packages),
r.FormatUpdatablePacksSummary(),
r.FormatExploitCveSummary(),
r.FormatMetasploitCveSummary(),
r.FormatAlertSummary(),
)
}
// FormatUpdatablePacksSummary returns a summary of updatable packages
func (r ScanResult) FormatUpdatablePacksSummary() string {
if !r.isDisplayUpdatableNum() {
return fmt.Sprintf("%d installed", len(r.Packages))
}
nUpdatable := 0
for _, p := range r.Packages {
if p.NewVersion == "" {
continue
}
if p.Version != p.NewVersion || p.Release != p.NewRelease {
nUpdatable++
}
}
return fmt.Sprintf("%d installed, %d updatable",
len(r.Packages),
nUpdatable)
}
// FormatExploitCveSummary returns a summary of exploit cve
func (r ScanResult) FormatExploitCveSummary() string {
nExploitCve := 0
for _, vuln := range r.ScannedCves {
if 0 < len(vuln.Exploits) {
nExploitCve++
}
}
return fmt.Sprintf("%d exploits", nExploitCve)
}
// FormatMetasploitCveSummary returns a summary of exploit cve
func (r ScanResult) FormatMetasploitCveSummary() string {
nMetasploitCve := 0
for _, vuln := range r.ScannedCves {
if 0 < len(vuln.Metasploits) {
nMetasploitCve++
}
}
return fmt.Sprintf("%d modules", nMetasploitCve)
}
// FormatAlertSummary returns a summary of CERT alerts
func (r ScanResult) FormatAlertSummary() string {
jaCnt := 0
enCnt := 0
for _, vuln := range r.ScannedCves {
if len(vuln.AlertDict.En) > 0 {
enCnt += len(vuln.AlertDict.En)
}
if len(vuln.AlertDict.Ja) > 0 {
jaCnt += len(vuln.AlertDict.Ja)
}
}
return fmt.Sprintf("en: %d, ja: %d alerts", enCnt, jaCnt)
}
func (r ScanResult) isDisplayUpdatableNum() bool {
var mode config.ScanMode
s, _ := config.Conf.Servers[r.ServerName]
mode = s.Mode
if mode.IsOffline() {
return false
}
if mode.IsFastRoot() || mode.IsDeep() {
return true
}
if mode.IsFast() {
switch r.Family {
case config.RedHat,
config.Oracle,
config.Debian,
config.Ubuntu,
config.Raspbian:
return false
default:
return true
}
}
return false
}
// IsContainer returns whether this ServerInfo is about container
func (r ScanResult) IsContainer() bool {
return 0 < len(r.Container.ContainerID)
}
// IsDeepScanMode checks if the scan mode is deep scan mode.
func (r ScanResult) IsDeepScanMode() bool {
for _, s := range r.Config.Scan.Servers {
for _, m := range s.ScanMode {
if m == "deep" {
return true
}
}
}
return false
}
// Container has Container information
type Container struct {
ContainerID string `json:"containerID"`
Name string `json:"name"`
Image string `json:"image"`
Type string `json:"type"`
UUID string `json:"uuid"`
}
// Platform has platform information
type Platform struct {
Name string `json:"name"` // aws or azure or gcp or other...
InstanceID string `json:"instanceID"`
}
// RemoveRaspbianPackFromResult is for Raspberry Pi and removes the Raspberry Pi dedicated package from ScanResult.
func (r ScanResult) RemoveRaspbianPackFromResult() ScanResult {
if r.Family != config.Raspbian {
return r
}
result := r
packs := make(Packages)
for _, pack := range r.Packages {
if !IsRaspbianPackage(pack.Name, pack.Version) {
packs[pack.Name] = pack
}
}
srcPacks := make(SrcPackages)
for _, pack := range r.SrcPackages {
if !IsRaspbianPackage(pack.Name, pack.Version) {
srcPacks[pack.Name] = pack
}
}
result.Packages = packs
result.SrcPackages = srcPacks
return result
}

View File

@@ -1,722 +0,0 @@
package models
import (
"reflect"
"testing"
"time"
"github.com/future-architect/vuls/config"
"github.com/k0kubun/pp"
)
func TestFilterByCvssOver(t *testing.T) {
type in struct {
over float64
rs ScanResult
}
var tests = []struct {
in in
out ScanResult
}{
{
in: in{
over: 7.0,
rs: ScanResult{
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
CveContents: NewCveContents(
CveContent{
Type: NvdXML,
CveID: "CVE-2017-0001",
Cvss2Score: 7.1,
LastModified: time.Time{},
},
),
},
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: NewCveContents(
CveContent{
Type: NvdXML,
CveID: "CVE-2017-0002",
Cvss2Score: 6.9,
LastModified: time.Time{},
},
),
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
CveContents: NewCveContents(
CveContent{
Type: NvdXML,
CveID: "CVE-2017-0003",
Cvss2Score: 6.9,
LastModified: time.Time{},
},
CveContent{
Type: Jvn,
CveID: "CVE-2017-0003",
Cvss2Score: 7.2,
LastModified: time.Time{},
},
),
},
},
},
},
out: ScanResult{
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
CveContents: NewCveContents(
CveContent{
Type: NvdXML,
CveID: "CVE-2017-0001",
Cvss2Score: 7.1,
LastModified: time.Time{},
},
),
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
CveContents: NewCveContents(
CveContent{
Type: NvdXML,
CveID: "CVE-2017-0003",
Cvss2Score: 6.9,
LastModified: time.Time{},
},
CveContent{
Type: Jvn,
CveID: "CVE-2017-0003",
Cvss2Score: 7.2,
LastModified: time.Time{},
},
),
},
},
},
},
// OVAL Severity
{
in: in{
over: 7.0,
rs: ScanResult{
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
CveContents: NewCveContents(
CveContent{
Type: Ubuntu,
CveID: "CVE-2017-0001",
Cvss2Severity: "HIGH",
LastModified: time.Time{},
},
),
},
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: NewCveContents(
CveContent{
Type: RedHat,
CveID: "CVE-2017-0002",
Cvss2Severity: "CRITICAL",
LastModified: time.Time{},
},
),
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
CveContents: NewCveContents(
CveContent{
Type: Oracle,
CveID: "CVE-2017-0003",
Cvss2Severity: "IMPORTANT",
LastModified: time.Time{},
},
),
},
},
},
},
out: ScanResult{
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
CveContents: NewCveContents(
CveContent{
Type: Ubuntu,
CveID: "CVE-2017-0001",
Cvss2Severity: "HIGH",
LastModified: time.Time{},
},
),
},
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: NewCveContents(
CveContent{
Type: RedHat,
CveID: "CVE-2017-0002",
Cvss2Severity: "CRITICAL",
LastModified: time.Time{},
},
),
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
CveContents: NewCveContents(
CveContent{
Type: Oracle,
CveID: "CVE-2017-0003",
Cvss2Severity: "IMPORTANT",
LastModified: time.Time{},
},
),
},
},
},
},
}
for _, tt := range tests {
actual := tt.in.rs.FilterByCvssOver(tt.in.over)
for k := range tt.out.ScannedCves {
if !reflect.DeepEqual(tt.out.ScannedCves[k], actual.ScannedCves[k]) {
o := pp.Sprintf("%v", tt.out.ScannedCves[k])
a := pp.Sprintf("%v", actual.ScannedCves[k])
t.Errorf("[%s] expected: %v\n actual: %v\n", k, o, a)
}
}
}
}
func TestFilterIgnoreCveIDs(t *testing.T) {
type in struct {
cves []string
rs ScanResult
}
var tests = []struct {
in in
out ScanResult
}{
{
in: in{
cves: []string{"CVE-2017-0002"},
rs: ScanResult{
ServerName: "name",
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
},
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
},
},
},
},
out: ScanResult{
ServerName: "name",
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
},
},
},
},
}
for _, tt := range tests {
config.Conf.Servers = map[string]config.ServerInfo{
"name": {IgnoreCves: tt.in.cves},
}
actual := tt.in.rs.FilterIgnoreCves()
for k := range tt.out.ScannedCves {
if !reflect.DeepEqual(tt.out.ScannedCves[k], actual.ScannedCves[k]) {
o := pp.Sprintf("%v", tt.out.ScannedCves[k])
a := pp.Sprintf("%v", actual.ScannedCves[k])
t.Errorf("[%s] expected: %v\n actual: %v\n", k, o, a)
}
}
for k := range actual.ScannedCves {
if !reflect.DeepEqual(tt.out.ScannedCves[k], actual.ScannedCves[k]) {
o := pp.Sprintf("%v", tt.out.ScannedCves[k])
a := pp.Sprintf("%v", actual.ScannedCves[k])
t.Errorf("[%s] expected: %v\n actual: %v\n", k, o, a)
}
}
}
}
func TestFilterIgnoreCveIDsContainer(t *testing.T) {
type in struct {
cves []string
rs ScanResult
}
var tests = []struct {
in in
out ScanResult
}{
{
in: in{
cves: []string{"CVE-2017-0002"},
rs: ScanResult{
ServerName: "name",
Container: Container{Name: "dockerA"},
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
},
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
},
},
},
},
out: ScanResult{
ServerName: "name",
Container: Container{Name: "dockerA"},
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
},
},
},
},
}
for _, tt := range tests {
config.Conf.Servers = map[string]config.ServerInfo{
"name": {
Containers: map[string]config.ContainerSetting{
"dockerA": {
IgnoreCves: tt.in.cves,
},
},
},
}
actual := tt.in.rs.FilterIgnoreCves()
for k := range tt.out.ScannedCves {
if !reflect.DeepEqual(tt.out.ScannedCves[k], actual.ScannedCves[k]) {
o := pp.Sprintf("%v", tt.out.ScannedCves[k])
a := pp.Sprintf("%v", actual.ScannedCves[k])
t.Errorf("[%s] expected: %v\n actual: %v\n", k, o, a)
}
}
for k := range actual.ScannedCves {
if !reflect.DeepEqual(tt.out.ScannedCves[k], actual.ScannedCves[k]) {
o := pp.Sprintf("%v", tt.out.ScannedCves[k])
a := pp.Sprintf("%v", actual.ScannedCves[k])
t.Errorf("[%s] expected: %v\n actual: %v\n", k, o, a)
}
}
}
}
func TestFilterUnfixed(t *testing.T) {
var tests = []struct {
in ScanResult
out ScanResult
}{
{
in: ScanResult{
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
AffectedPackages: PackageFixStatuses{
{
Name: "a",
NotFixedYet: true,
},
},
},
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
AffectedPackages: PackageFixStatuses{
{
Name: "b",
NotFixedYet: false,
},
},
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
AffectedPackages: PackageFixStatuses{
{
Name: "c",
NotFixedYet: true,
},
{
Name: "d",
NotFixedYet: false,
},
},
},
},
},
out: ScanResult{
ScannedCves: VulnInfos{
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
AffectedPackages: PackageFixStatuses{
{
Name: "b",
NotFixedYet: false,
},
},
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
AffectedPackages: PackageFixStatuses{
{
Name: "c",
NotFixedYet: true,
},
{
Name: "d",
NotFixedYet: false,
},
},
},
},
},
},
}
for i, tt := range tests {
config.Conf.IgnoreUnfixed = true
actual := tt.in.FilterUnfixed()
if !reflect.DeepEqual(tt.out.ScannedCves, actual.ScannedCves) {
o := pp.Sprintf("%v", tt.out.ScannedCves)
a := pp.Sprintf("%v", actual.ScannedCves)
t.Errorf("[%d] expected: %v\n actual: %v\n", i, o, a)
}
}
}
func TestFilterIgnorePkgs(t *testing.T) {
type in struct {
ignorePkgsRegexp []string
rs ScanResult
}
var tests = []struct {
in in
out ScanResult
}{
{
in: in{
ignorePkgsRegexp: []string{"^kernel"},
rs: ScanResult{
ServerName: "name",
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
AffectedPackages: PackageFixStatuses{
{Name: "kernel"},
},
},
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
},
},
},
},
out: ScanResult{
ServerName: "name",
ScannedCves: VulnInfos{
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
},
},
},
},
{
in: in{
ignorePkgsRegexp: []string{"^kernel"},
rs: ScanResult{
ServerName: "name",
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
AffectedPackages: PackageFixStatuses{
{Name: "kernel"},
{Name: "vim"},
},
},
},
},
},
out: ScanResult{
ServerName: "name",
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
AffectedPackages: PackageFixStatuses{
{Name: "kernel"},
{Name: "vim"},
},
},
},
},
},
{
in: in{
ignorePkgsRegexp: []string{"^kernel", "^vim", "^bind"},
rs: ScanResult{
ServerName: "name",
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
AffectedPackages: PackageFixStatuses{
{Name: "kernel"},
{Name: "vim"},
},
},
},
},
},
out: ScanResult{
ServerName: "name",
ScannedCves: VulnInfos{},
},
},
}
for _, tt := range tests {
config.Conf.Servers = map[string]config.ServerInfo{
"name": {IgnorePkgsRegexp: tt.in.ignorePkgsRegexp},
}
actual := tt.in.rs.FilterIgnorePkgs()
for k := range tt.out.ScannedCves {
if !reflect.DeepEqual(tt.out.ScannedCves[k], actual.ScannedCves[k]) {
o := pp.Sprintf("%v", tt.out.ScannedCves[k])
a := pp.Sprintf("%v", actual.ScannedCves[k])
t.Errorf("[%s] expected: %v\n actual: %v\n", k, o, a)
}
}
for k := range actual.ScannedCves {
if !reflect.DeepEqual(tt.out.ScannedCves[k], actual.ScannedCves[k]) {
o := pp.Sprintf("%v", tt.out.ScannedCves[k])
a := pp.Sprintf("%v", actual.ScannedCves[k])
t.Errorf("[%s] expected: %v\n actual: %v\n", k, o, a)
}
}
}
}
func TestFilterIgnorePkgsContainer(t *testing.T) {
type in struct {
ignorePkgsRegexp []string
rs ScanResult
}
var tests = []struct {
in in
out ScanResult
}{
{
in: in{
ignorePkgsRegexp: []string{"^kernel"},
rs: ScanResult{
ServerName: "name",
Container: Container{Name: "dockerA"},
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
AffectedPackages: PackageFixStatuses{
{Name: "kernel"},
},
},
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
},
},
},
},
out: ScanResult{
ServerName: "name",
Container: Container{Name: "dockerA"},
ScannedCves: VulnInfos{
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
},
},
},
},
{
in: in{
ignorePkgsRegexp: []string{"^kernel"},
rs: ScanResult{
ServerName: "name",
Container: Container{Name: "dockerA"},
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
AffectedPackages: PackageFixStatuses{
{Name: "kernel"},
{Name: "vim"},
},
},
},
},
},
out: ScanResult{
ServerName: "name",
Container: Container{Name: "dockerA"},
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
AffectedPackages: PackageFixStatuses{
{Name: "kernel"},
{Name: "vim"},
},
},
},
},
},
{
in: in{
ignorePkgsRegexp: []string{"^kernel", "^vim", "^bind"},
rs: ScanResult{
ServerName: "name",
Container: Container{Name: "dockerA"},
ScannedCves: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
AffectedPackages: PackageFixStatuses{
{Name: "kernel"},
{Name: "vim"},
},
},
},
},
},
out: ScanResult{
ServerName: "name",
Container: Container{Name: "dockerA"},
ScannedCves: VulnInfos{},
},
},
}
for _, tt := range tests {
config.Conf.Servers = map[string]config.ServerInfo{
"name": {
Containers: map[string]config.ContainerSetting{
"dockerA": {
IgnorePkgsRegexp: tt.in.ignorePkgsRegexp,
},
},
},
}
actual := tt.in.rs.FilterIgnorePkgs()
for k := range tt.out.ScannedCves {
if !reflect.DeepEqual(tt.out.ScannedCves[k], actual.ScannedCves[k]) {
o := pp.Sprintf("%v", tt.out.ScannedCves[k])
a := pp.Sprintf("%v", actual.ScannedCves[k])
t.Errorf("[%s] expected: %v\n actual: %v\n", k, o, a)
}
}
for k := range actual.ScannedCves {
if !reflect.DeepEqual(tt.out.ScannedCves[k], actual.ScannedCves[k]) {
o := pp.Sprintf("%v", tt.out.ScannedCves[k])
a := pp.Sprintf("%v", actual.ScannedCves[k])
t.Errorf("[%s] expected: %v\n actual: %v\n", k, o, a)
}
}
}
}
func TestIsDisplayUpdatableNum(t *testing.T) {
var tests = []struct {
mode []byte
family string
expected bool
}{
{
mode: []byte{config.Offline},
expected: false,
},
{
mode: []byte{config.FastRoot},
expected: true,
},
{
mode: []byte{config.Deep},
expected: true,
},
{
mode: []byte{config.Fast},
family: config.RedHat,
expected: false,
},
{
mode: []byte{config.Fast},
family: config.Oracle,
expected: false,
},
{
mode: []byte{config.Fast},
family: config.Debian,
expected: false,
},
{
mode: []byte{config.Fast},
family: config.Ubuntu,
expected: false,
},
{
mode: []byte{config.Fast},
family: config.Raspbian,
expected: false,
},
{
mode: []byte{config.Fast},
family: config.CentOS,
expected: true,
},
{
mode: []byte{config.Fast},
family: config.Amazon,
expected: true,
},
{
mode: []byte{config.Fast},
family: config.FreeBSD,
expected: true,
},
{
mode: []byte{config.Fast},
family: config.OpenSUSE,
expected: true,
},
{
mode: []byte{config.Fast},
family: config.Alpine,
expected: true,
},
}
for i, tt := range tests {
mode := config.ScanMode{}
for _, m := range tt.mode {
mode.Set(m)
}
config.Conf.Servers = map[string]config.ServerInfo{
"name": {Mode: mode},
}
r := ScanResult{
ServerName: "name",
Family: tt.family,
}
act := r.isDisplayUpdatableNum()
if tt.expected != act {
t.Errorf("[%d] expected %#v, actual %#v", i, tt.expected, act)
}
}
}

View File

@@ -1,97 +0,0 @@
package models
import (
"strings"
cvedict "github.com/kotakanbe/go-cve-dictionary/models"
)
// ConvertJvnToModel convert JVN to CveContent
func ConvertJvnToModel(cveID string, jvn *cvedict.Jvn) *CveContent {
if jvn == nil {
return nil
}
// var cpes = []Cpe{}
// for _, c := range jvn.Cpes {
// cpes = append(cpes, Cpe{
// FormattedString: c.FormattedString,
// URI: c.URI,
// })
// }
refs := []Reference{}
for _, r := range jvn.References {
refs = append(refs, Reference{
Link: r.Link,
Source: r.Source,
})
}
return &CveContent{
Type: Jvn,
CveID: cveID,
Title: jvn.Title,
Summary: jvn.Summary,
Cvss2Score: jvn.Cvss2.BaseScore,
Cvss2Vector: jvn.Cvss2.VectorString,
Cvss2Severity: jvn.Cvss2.Severity,
Cvss3Score: jvn.Cvss3.BaseScore,
Cvss3Vector: jvn.Cvss3.VectorString,
Cvss3Severity: jvn.Cvss3.BaseSeverity,
SourceLink: jvn.JvnLink,
// Cpes: cpes,
References: refs,
Published: jvn.PublishedDate,
LastModified: jvn.LastModifiedDate,
}
}
// ConvertNvdJSONToModel convert NVD to CveContent
func ConvertNvdJSONToModel(cveID string, nvd *cvedict.NvdJSON) *CveContent {
if nvd == nil {
return nil
}
// var cpes = []Cpe{}
// for _, c := range nvd.Cpes {
// cpes = append(cpes, Cpe{
// FormattedString: c.FormattedString,
// URI: c.URI,
// })
// }
var refs = []Reference{}
for _, r := range nvd.References {
refs = append(refs, Reference{
Link: r.Link,
Source: r.Source,
})
}
cweIDs := []string{}
for _, cid := range nvd.Cwes {
cweIDs = append(cweIDs, cid.CweID)
}
desc := []string{}
for _, d := range nvd.Descriptions {
desc = append(desc, d.Value)
}
return &CveContent{
Type: Nvd,
CveID: cveID,
Summary: strings.Join(desc, "\n"),
Cvss2Score: nvd.Cvss2.BaseScore,
Cvss2Vector: nvd.Cvss2.VectorString,
Cvss2Severity: nvd.Cvss2.Severity,
Cvss3Score: nvd.Cvss3.BaseScore,
Cvss3Vector: nvd.Cvss3.VectorString,
Cvss3Severity: nvd.Cvss3.BaseSeverity,
SourceLink: "https://nvd.nist.gov/vuln/detail/" + cveID,
// Cpes: cpes,
CweIDs: cweIDs,
References: refs,
Published: nvd.PublishedDate,
LastModified: nvd.LastModifiedDate,
}
}

View File

@@ -1,933 +0,0 @@
package models
import (
"bytes"
"fmt"
"sort"
"strings"
"time"
"github.com/future-architect/vuls/config"
exploitmodels "github.com/mozqnet/go-exploitdb/models"
)
// VulnInfos has a map of VulnInfo
// Key: CveID
type VulnInfos map[string]VulnInfo
// Find elements that matches the function passed in argument
func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {
filtered := VulnInfos{}
for _, vv := range v {
if f(vv) {
filtered[vv.CveID] = vv
}
}
return filtered
}
// FindScoredVulns return scored vulnerabilities
func (v VulnInfos) FindScoredVulns() VulnInfos {
return v.Find(func(vv VulnInfo) bool {
if 0 < vv.MaxCvss2Score().Value.Score ||
0 < vv.MaxCvss3Score().Value.Score {
return true
}
return false
})
}
// ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID
func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {
for k := range v {
sorted = append(sorted, v[k])
}
sort.Slice(sorted, func(i, j int) bool {
maxI := sorted[i].MaxCvssScore()
maxJ := sorted[j].MaxCvssScore()
if maxI.Value.Score != maxJ.Value.Score {
return maxJ.Value.Score < maxI.Value.Score
}
return sorted[i].CveID < sorted[j].CveID
})
return
}
// CountGroupBySeverity summarize the number of CVEs group by CVSSv2 Severity
func (v VulnInfos) CountGroupBySeverity() map[string]int {
m := map[string]int{}
for _, vInfo := range v {
score := vInfo.MaxCvss2Score().Value.Score
if score < 0.1 {
score = vInfo.MaxCvss3Score().Value.Score
}
switch {
case 7.0 <= score:
m["High"]++
case 4.0 <= score:
m["Medium"]++
case 0 < score:
m["Low"]++
default:
m["Unknown"]++
}
}
return m
}
// FormatCveSummary summarize the number of CVEs group by CVSSv2 Severity
func (v VulnInfos) FormatCveSummary() string {
m := v.CountGroupBySeverity()
if config.Conf.IgnoreUnscoredCves {
return fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d)",
m["High"]+m["Medium"]+m["Low"], m["High"], m["Medium"], m["Low"])
}
return fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d ?:%d)",
m["High"]+m["Medium"]+m["Low"]+m["Unknown"],
m["High"], m["Medium"], m["Low"], m["Unknown"])
}
// FormatFixedStatus summarize the number of cves are fixed.
func (v VulnInfos) FormatFixedStatus(packs Packages) string {
total, fixed := 0, 0
for _, vInfo := range v {
if len(vInfo.CpeURIs) != 0 {
continue
}
total++
if vInfo.PatchStatus(packs) == "fixed" {
fixed++
}
}
return fmt.Sprintf("%d/%d Fixed", fixed, total)
}
// PackageFixStatuses is a list of PackageStatus
type PackageFixStatuses []PackageFixStatus
// Names return a slice of package names
func (ps PackageFixStatuses) Names() (names []string) {
for _, p := range ps {
names = append(names, p.Name)
}
return names
}
// Store insert given pkg if missing, update pkg if exists
func (ps PackageFixStatuses) Store(pkg PackageFixStatus) PackageFixStatuses {
for i, p := range ps {
if p.Name == pkg.Name {
ps[i] = pkg
return ps
}
}
ps = append(ps, pkg)
return ps
}
// Sort by Name
func (ps PackageFixStatuses) Sort() {
sort.Slice(ps, func(i, j int) bool {
return ps[i].Name < ps[j].Name
})
return
}
// PackageFixStatus has name and other status abount the package
type PackageFixStatus struct {
Name string `json:"name,omitempty"`
NotFixedYet bool `json:"notFixedYet,omitempty"`
FixState string `json:"fixState,omitempty"`
FixedIn string `json:"fixedIn,omitempty"`
}
// VulnInfo has a vulnerability information and unsecure packages
type VulnInfo struct {
CveID string `json:"cveID,omitempty"`
Confidences Confidences `json:"confidences,omitempty"`
AffectedPackages PackageFixStatuses `json:"affectedPackages,omitempty"`
DistroAdvisories DistroAdvisories `json:"distroAdvisories,omitempty"` // for Aamazon, RHEL, FreeBSD
CveContents CveContents `json:"cveContents,omitempty"`
Exploits []Exploit `json:"exploits,omitempty"`
Metasploits []Metasploit `json:"metasploits,omitempty"`
AlertDict AlertDict `json:"alertDict,omitempty"`
CpeURIs []string `json:"cpeURIs,omitempty"` // CpeURIs related to this CVE defined in config.toml
GitHubSecurityAlerts GitHubSecurityAlerts `json:"gitHubSecurityAlerts,omitempty"`
WpPackageFixStats WpPackageFixStats `json:"wpPackageFixStats,omitempty"`
LibraryFixedIns LibraryFixedIns `json:"libraryFixedIns,omitempty"`
VulnType string `json:"vulnType,omitempty"`
}
// Alert has XCERT alert information
type Alert struct {
URL string `json:"url,omitempty"`
Title string `json:"title,omitempty"`
Team string `json:"team,omitempty"`
}
// GitHubSecurityAlerts is a list of GitHubSecurityAlert
type GitHubSecurityAlerts []GitHubSecurityAlert
// Add adds given arg to the slice and return the slice (immutable)
func (g GitHubSecurityAlerts) Add(alert GitHubSecurityAlert) GitHubSecurityAlerts {
for _, a := range g {
if a.PackageName == alert.PackageName {
return g
}
}
return append(g, alert)
}
// Names return a slice of lib names
func (g GitHubSecurityAlerts) Names() (names []string) {
for _, a := range g {
names = append(names, a.PackageName)
}
return names
}
// GitHubSecurityAlert has detected CVE-ID, PackageName, Status fetched via GitHub API
type GitHubSecurityAlert struct {
PackageName string `json:"packageName"`
FixedIn string `json:"fixedIn"`
AffectedRange string `json:"affectedRange"`
Dismissed bool `json:"dismissed"`
DismissedAt time.Time `json:"dismissedAt"`
DismissReason string `json:"dismissReason"`
}
// LibraryFixedIns is a list of Library's FixedIn
type LibraryFixedIns []LibraryFixedIn
// Names return a slice of names
func (lfs LibraryFixedIns) Names() (names []string) {
for _, lf := range lfs {
names = append(names, lf.Name)
}
return names
}
// WpPackageFixStats is a list of WpPackageFixStatus
type WpPackageFixStats []WpPackageFixStatus
// Names return a slice of names
func (ws WpPackageFixStats) Names() (names []string) {
for _, w := range ws {
names = append(names, w.Name)
}
return names
}
// WpPackages has a list of WpPackage
type WpPackages []WpPackage
// Add adds given arg to the slice and return the slice (immutable)
func (g WpPackages) Add(pkg WpPackage) WpPackages {
for _, a := range g {
if a.Name == pkg.Name {
return g
}
}
return append(g, pkg)
}
// Titles returns tilte (TUI)
func (v VulnInfo) Titles(lang, myFamily string) (values []CveContentStr) {
if lang == "ja" {
if cont, found := v.CveContents[Jvn]; found && 0 < len(cont.Title) {
values = append(values, CveContentStr{Jvn, cont.Title})
}
}
// RedHat API has one line title.
if cont, found := v.CveContents[RedHatAPI]; found && 0 < len(cont.Title) {
values = append(values, CveContentStr{RedHatAPI, cont.Title})
}
order := CveContentTypes{Trivy, Nvd, NvdXML, NewCveContentType(myFamily)}
order = append(order, AllCveContetTypes.Except(append(order, Jvn)...)...)
for _, ctype := range order {
// Only JVN has meaningful title. so return first 100 char of summary
if cont, found := v.CveContents[ctype]; found && 0 < len(cont.Summary) {
summary := strings.Replace(cont.Summary, "\n", " ", -1)
values = append(values, CveContentStr{
Type: ctype,
Value: summary,
})
}
}
for _, adv := range v.DistroAdvisories {
values = append(values, CveContentStr{
Type: "Vendor",
Value: strings.Replace(adv.Description, "\n", " ", -1),
})
}
if len(values) == 0 {
values = []CveContentStr{{
Type: Unknown,
Value: "-",
}}
}
return
}
// Summaries returns summaries
func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) {
if lang == "ja" {
if cont, found := v.CveContents[Jvn]; found && 0 < len(cont.Summary) {
summary := cont.Title
summary += "\n" + strings.Replace(
strings.Replace(cont.Summary, "\n", " ", -1), "\r", " ", -1)
values = append(values, CveContentStr{Jvn, summary})
}
}
order := CveContentTypes{Trivy, NewCveContentType(myFamily), Nvd, NvdXML}
order = append(order, AllCveContetTypes.Except(append(order, Jvn)...)...)
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found && 0 < len(cont.Summary) {
summary := strings.Replace(cont.Summary, "\n", " ", -1)
values = append(values, CveContentStr{
Type: ctype,
Value: summary,
})
}
}
for _, adv := range v.DistroAdvisories {
values = append(values, CveContentStr{
Type: "Vendor",
Value: adv.Description,
})
}
if v, ok := v.CveContents[WPVulnDB]; ok {
values = append(values, CveContentStr{
Type: "WPVDB",
Value: v.Title,
})
}
if len(values) == 0 {
return []CveContentStr{{
Type: Unknown,
Value: "-",
}}
}
return
}
// Mitigations returns mitigations
func (v VulnInfo) Mitigations(myFamily string) (values []CveContentStr) {
order := CveContentTypes{RedHatAPI}
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found && 0 < len(cont.Mitigation) {
values = append(values, CveContentStr{
Type: ctype,
Value: cont.Mitigation,
})
}
}
if len(values) == 0 {
return []CveContentStr{{
Type: Unknown,
Value: "-",
}}
}
return
}
// Cvss2Scores returns CVSS V2 Scores
func (v VulnInfo) Cvss2Scores(myFamily string) (values []CveContentCvss) {
order := []CveContentType{Nvd, NvdXML, RedHatAPI, RedHat, Jvn}
if myFamily != config.RedHat && myFamily != config.CentOS {
order = append(order, NewCveContentType(myFamily))
}
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found {
if cont.Cvss2Score == 0 || cont.Cvss2Severity == "" {
continue
}
// https://nvd.nist.gov/vuln-metrics/cvss
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS2,
Score: cont.Cvss2Score,
Vector: cont.Cvss2Vector,
Severity: strings.ToUpper(cont.Cvss2Severity),
},
})
}
}
for _, adv := range v.DistroAdvisories {
if adv.Severity != "" {
values = append(values, CveContentCvss{
Type: "Advisory",
Value: Cvss{
Type: CVSS2,
Score: severityToV2ScoreRoughly(adv.Severity),
CalculatedBySeverity: true,
Vector: "-",
Severity: strings.ToUpper(adv.Severity),
},
})
}
}
// An OVAL entry in Ubuntu and Debian has only severity (CVSS score isn't included).
// Show severity and dummy score calculated roughly.
order = append(order, AllCveContetTypes.Except(order...)...)
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found &&
cont.Cvss2Score == 0 &&
cont.Cvss3Score == 0 &&
cont.Cvss2Severity != "" {
values = append(values, CveContentCvss{
Type: cont.Type,
Value: Cvss{
Type: CVSS2,
Score: severityToV2ScoreRoughly(cont.Cvss2Severity),
CalculatedBySeverity: true,
Vector: "-",
Severity: strings.ToUpper(cont.Cvss2Severity),
},
})
}
}
return
}
// Cvss3Scores returns CVSS V3 Score
func (v VulnInfo) Cvss3Scores() (values []CveContentCvss) {
order := []CveContentType{Nvd, RedHatAPI, RedHat, Jvn}
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found {
// https://nvd.nist.gov/vuln-metrics/cvss
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS3,
Score: cont.Cvss3Score,
Vector: cont.Cvss3Vector,
Severity: strings.ToUpper(cont.Cvss3Severity),
},
})
}
}
if cont, found := v.CveContents[Trivy]; found && cont.Cvss3Severity != "" {
values = append(values, CveContentCvss{
Type: Trivy,
Value: Cvss{
Type: CVSS3,
Score: severityToV2ScoreRoughly(cont.Cvss3Severity),
Severity: strings.ToUpper(cont.Cvss3Severity),
},
})
}
return
}
// MaxCvss3Score returns Max CVSS V3 Score
func (v VulnInfo) MaxCvss3Score() CveContentCvss {
order := []CveContentType{Nvd, RedHat, RedHatAPI, Jvn}
max := 0.0
value := CveContentCvss{
Type: Unknown,
Value: Cvss{Type: CVSS3},
}
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found && max < cont.Cvss3Score {
// https://nvd.nist.gov/vuln-metrics/cvss
value = CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS3,
Score: cont.Cvss3Score,
Vector: cont.Cvss3Vector,
Severity: strings.ToUpper(cont.Cvss3Severity),
},
}
max = cont.Cvss3Score
}
}
return value
}
// MaxCvssScore returns max CVSS Score
// If there is no CVSS Score, return Severity as a numerical value.
func (v VulnInfo) MaxCvssScore() CveContentCvss {
v3Max := v.MaxCvss3Score()
v2Max := v.MaxCvss2Score()
max := v3Max
if max.Type == Unknown {
return v2Max
}
if max.Value.Score < v2Max.Value.Score && !v2Max.Value.CalculatedBySeverity {
max = v2Max
}
return max
}
// MaxCvss2Score returns Max CVSS V2 Score
func (v VulnInfo) MaxCvss2Score() CveContentCvss {
order := []CveContentType{Nvd, NvdXML, RedHat, RedHatAPI, Jvn}
max := 0.0
value := CveContentCvss{
Type: Unknown,
Value: Cvss{Type: CVSS2},
}
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found && max < cont.Cvss2Score {
// https://nvd.nist.gov/vuln-metrics/cvss
value = CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS2,
Score: cont.Cvss2Score,
Vector: cont.Cvss2Vector,
Severity: strings.ToUpper(cont.Cvss2Severity),
},
}
max = cont.Cvss2Score
}
}
if 0 < max {
return value
}
// If CVSS score isn't on NVD, RedHat and JVN, use OVAL and advisory Severity.
// Convert severity to cvss srore roughly, then returns max severity.
// Only Ubuntu, RedHat and Oracle have severity data in OVAL.
order = []CveContentType{Ubuntu, RedHat, Oracle}
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found && 0 < len(cont.Cvss2Severity) {
score := severityToV2ScoreRoughly(cont.Cvss2Severity)
if max < score {
value = CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS2,
Score: score,
CalculatedBySeverity: true,
Vector: cont.Cvss2Vector,
Severity: strings.ToUpper(cont.Cvss2Severity),
},
}
}
max = score
}
}
// Only RedHat, Oracle and Amazon has severity data in advisory.
for _, adv := range v.DistroAdvisories {
if adv.Severity != "" {
score := severityToV2ScoreRoughly(adv.Severity)
if max < score {
value = CveContentCvss{
Type: "Vendor",
Value: Cvss{
Type: CVSS2,
Score: score,
CalculatedBySeverity: true,
Vector: "-",
Severity: adv.Severity,
},
}
}
}
}
return value
}
// AttackVector returns attack vector string
func (v VulnInfo) AttackVector() string {
for _, cnt := range v.CveContents {
if strings.HasPrefix(cnt.Cvss2Vector, "AV:N") ||
strings.Contains(cnt.Cvss3Vector, "AV:N") {
return "AV:N"
} else if strings.HasPrefix(cnt.Cvss2Vector, "AV:A") ||
strings.Contains(cnt.Cvss3Vector, "AV:A") {
return "AV:A"
} else if strings.HasPrefix(cnt.Cvss2Vector, "AV:L") ||
strings.Contains(cnt.Cvss3Vector, "AV:L") {
return "AV:L"
} else if strings.Contains(cnt.Cvss3Vector, "AV:P") {
// no AV:P in CVSS v2
return "AV:P"
}
}
if cont, found := v.CveContents[DebianSecurityTracker]; found {
if attackRange, found := cont.Optional["attack range"]; found {
return attackRange
}
}
return ""
}
// PatchStatus returns fixed or unfixed string
func (v VulnInfo) PatchStatus(packs Packages) string {
// Vuls don't know patch status of the CPE
if len(v.CpeURIs) != 0 {
return ""
}
for _, p := range v.AffectedPackages {
if p.NotFixedYet {
return "unfixed"
}
// Fast and offline mode can not get the candidate version.
// Vuls can be considered as 'fixed' if not-fixed-yet==true and
// the fixed-in-version (information in the oval) is not an empty.
if p.FixedIn != "" {
continue
}
// fast, offline mode doesn't have new version
if pack, ok := packs[p.Name]; ok {
if pack.NewVersion == "" {
return "unknown"
}
}
}
return "fixed"
}
// CveContentCvss has CVSS information
type CveContentCvss struct {
Type CveContentType `json:"type"`
Value Cvss `json:"value"`
}
// CvssType Represent the type of CVSS
type CvssType string
const (
// CVSS2 means CVSS vesion2
CVSS2 CvssType = "2"
// CVSS3 means CVSS vesion3
CVSS3 CvssType = "3"
)
// Cvss has CVSS Score
type Cvss struct {
Type CvssType `json:"type"`
Score float64 `json:"score"`
CalculatedBySeverity bool `json:"calculatedBySeverity"`
Vector string `json:"vector"`
Severity string `json:"severity"`
}
// Format CVSS Score and Vector
func (c Cvss) Format() string {
if c.Score == 0 || c.Vector == "" {
return c.Severity
}
switch c.Type {
case CVSS2:
return fmt.Sprintf("%3.1f/%s %s", c.Score, c.Vector, c.Severity)
case CVSS3:
return fmt.Sprintf("%3.1f/%s %s", c.Score, c.Vector, c.Severity)
}
return ""
}
// Amazon Linux Security Advisory
// Critical, Important, Medium, Low
// https://alas.aws.amazon.com/
//
// RedHat, Oracle OVAL
// Critical, Important, Moderate, Low
// https://access.redhat.com/security/updates/classification
//
// Ubuntu OVAL
// Critical, High, Medium, Low
// https://wiki.ubuntu.com/Bugs/Importance
// https://people.canonical.com/~ubuntu-security/cve/priority.html
func severityToV2ScoreRoughly(severity string) float64 {
switch strings.ToUpper(severity) {
case "CRITICAL":
return 10.0
case "IMPORTANT", "HIGH":
return 8.9
case "MODERATE", "MEDIUM":
return 6.9
case "LOW":
return 3.9
}
return 0
}
// FormatMaxCvssScore returns Max CVSS Score
func (v VulnInfo) FormatMaxCvssScore() string {
max := v.MaxCvssScore()
return fmt.Sprintf("%3.1f %s (%s)",
max.Value.Score,
strings.ToUpper(max.Value.Severity),
max.Type)
}
// Cvss2CalcURL returns CVSS v2 caluclator's URL
func (v VulnInfo) Cvss2CalcURL() string {
return "https://nvd.nist.gov/vuln-metrics/cvss/v2-calculator?name=" + v.CveID
}
// Cvss3CalcURL returns CVSS v3 caluclator's URL
func (v VulnInfo) Cvss3CalcURL() string {
return "https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?name=" + v.CveID
}
// VendorLinks returns links of vendor support's URL
func (v VulnInfo) VendorLinks(family string) map[string]string {
links := map[string]string{}
if strings.HasPrefix(v.CveID, "WPVDBID") {
links["WPVulnDB"] = fmt.Sprintf("https://wpvulndb.com/vulnerabilities/%s",
strings.TrimPrefix(v.CveID, "WPVDBID-"))
return links
}
switch family {
case config.RedHat, config.CentOS:
links["RHEL-CVE"] = "https://access.redhat.com/security/cve/" + v.CveID
for _, advisory := range v.DistroAdvisories {
aidURL := strings.Replace(advisory.AdvisoryID, ":", "-", -1)
links[advisory.AdvisoryID] = fmt.Sprintf("https://rhn.redhat.com/errata/%s.html", aidURL)
}
return links
case config.Oracle:
links["Oracle-CVE"] = fmt.Sprintf("https://linux.oracle.com/cve/%s.html", v.CveID)
for _, advisory := range v.DistroAdvisories {
links[advisory.AdvisoryID] =
fmt.Sprintf("https://linux.oracle.com/errata/%s.html", advisory.AdvisoryID)
}
return links
case config.Amazon:
links["RHEL-CVE"] = "https://access.redhat.com/security/cve/" + v.CveID
for _, advisory := range v.DistroAdvisories {
if strings.HasPrefix(advisory.AdvisoryID, "ALAS2") {
links[advisory.AdvisoryID] =
fmt.Sprintf("https://alas.aws.amazon.com/AL2/%s.html",
strings.Replace(advisory.AdvisoryID, "ALAS2", "ALAS", -1))
} else {
links[advisory.AdvisoryID] =
fmt.Sprintf("https://alas.aws.amazon.com/%s.html", advisory.AdvisoryID)
}
}
return links
case config.Ubuntu:
links["Ubuntu-CVE"] = "http://people.ubuntu.com/~ubuntu-security/cve/" + v.CveID
return links
case config.Debian:
links["Debian-CVE"] = "https://security-tracker.debian.org/tracker/" + v.CveID
case config.SUSEEnterpriseServer:
links["SUSE-CVE"] = "https://www.suse.com/security/cve/" + v.CveID
case config.FreeBSD:
for _, advisory := range v.DistroAdvisories {
links["FreeBSD-VuXML"] = fmt.Sprintf("https://vuxml.freebsd.org/freebsd/%s.html", advisory.AdvisoryID)
}
return links
}
return links
}
// DistroAdvisories is a list of DistroAdvisory
type DistroAdvisories []DistroAdvisory
// AppendIfMissing appends if missing
func (advs *DistroAdvisories) AppendIfMissing(adv *DistroAdvisory) bool {
for _, a := range *advs {
if a.AdvisoryID == adv.AdvisoryID {
return false
}
}
*advs = append(*advs, *adv)
return true
}
// DistroAdvisory has Amazon Linux, RHEL, FreeBSD Security Advisory information.
type DistroAdvisory struct {
AdvisoryID string `json:"advisoryID"`
Severity string `json:"severity"`
Issued time.Time `json:"issued"`
Updated time.Time `json:"updated"`
Description string `json:"description"`
}
// Format the distro advisory information
func (p DistroAdvisory) Format() string {
if p.AdvisoryID == "" {
return ""
}
var delim bytes.Buffer
for i := 0; i < len(p.AdvisoryID); i++ {
delim.WriteString("-")
}
buf := []string{p.AdvisoryID, delim.String(), p.Description}
return strings.Join(buf, "\n")
}
// Exploit :
type Exploit struct {
ExploitType exploitmodels.ExploitType `json:"exploitType"`
ID string `json:"id"`
URL string `json:"url"`
Description string `json:"description"`
DocumentURL *string `json:"documentURL,omitempty"`
ShellCodeURL *string `json:"shellCodeURL,omitempty"`
BinaryURL *string `json:"binaryURL,omitempty"`
}
// Metasploit :
type Metasploit struct {
Name string `json:"name"`
Title string `json:"title"`
Description string `json:"description,omitempty"`
URLs []string `json:",omitempty"`
}
// AlertDict has target cve's JPCERT and USCERT alert data
type AlertDict struct {
Ja []Alert `json:"ja"`
En []Alert `json:"en"`
}
// FormatSource returns which source has this alert
func (a AlertDict) FormatSource() string {
s := []string{}
if len(a.En) != 0 {
s = append(s, "USCERT")
}
if len(a.Ja) != 0 {
s = append(s, "JPCERT")
}
return strings.Join(s, "/")
}
// Confidences is a list of Confidence
type Confidences []Confidence
// AppendIfMissing appends confidence to the list if missiong
func (cs *Confidences) AppendIfMissing(confidence Confidence) {
for _, c := range *cs {
if c.DetectionMethod == confidence.DetectionMethod {
return
}
}
*cs = append(*cs, confidence)
}
// SortByConfident sorts Confidences
func (cs Confidences) SortByConfident() Confidences {
sort.Slice(cs, func(i, j int) bool {
return cs[i].SortOrder < cs[j].SortOrder
})
return cs
}
// Confidence is a ranking how confident the CVE-ID was deteted correctly
// Score: 0 - 100
type Confidence struct {
Score int `json:"score"`
DetectionMethod DetectionMethod `json:"detectionMethod"`
SortOrder int `json:"-"`
}
func (c Confidence) String() string {
return fmt.Sprintf("%d / %s", c.Score, c.DetectionMethod)
}
// DetectionMethod indicates
// - How to detect the CveID
// - How to get the changelog difference between installed and candidate version
type DetectionMethod string
const (
// CpeNameMatchStr is a String representation of CpeNameMatch
CpeNameMatchStr = "CpeNameMatch"
// YumUpdateSecurityMatchStr is a String representation of YumUpdateSecurityMatch
YumUpdateSecurityMatchStr = "YumUpdateSecurityMatch"
// PkgAuditMatchStr is a String representation of PkgAuditMatch
PkgAuditMatchStr = "PkgAuditMatch"
// OvalMatchStr is a String representation of OvalMatch
OvalMatchStr = "OvalMatch"
// RedHatAPIStr is a String representation of RedHatAPIMatch
RedHatAPIStr = "RedHatAPIMatch"
// DebianSecurityTrackerMatchStr is a String representation of DebianSecurityTrackerMatch
DebianSecurityTrackerMatchStr = "DebianSecurityTrackerMatch"
// TrivyMatchStr is a String representation of Trivy
TrivyMatchStr = "TrivyMatch"
// ChangelogExactMatchStr is a String representation of ChangelogExactMatch
ChangelogExactMatchStr = "ChangelogExactMatch"
// ChangelogLenientMatchStr is a String representation of ChangelogLenientMatch
ChangelogLenientMatchStr = "ChangelogLenientMatch"
// GitHubMatchStr is a String representation of GitHubMatch
GitHubMatchStr = "GitHubMatch"
// WPVulnDBMatchStr is a String representation of WordPress VulnDB scanning
WPVulnDBMatchStr = "WPVulnDBMatch"
// FailedToGetChangelog is a String representation of FailedToGetChangelog
FailedToGetChangelog = "FailedToGetChangelog"
// FailedToFindVersionInChangelog is a String representation of FailedToFindVersionInChangelog
FailedToFindVersionInChangelog = "FailedToFindVersionInChangelog"
)
var (
// CpeNameMatch is a ranking how confident the CVE-ID was deteted correctly
CpeNameMatch = Confidence{100, CpeNameMatchStr, 1}
// YumUpdateSecurityMatch is a ranking how confident the CVE-ID was deteted correctly
YumUpdateSecurityMatch = Confidence{100, YumUpdateSecurityMatchStr, 2}
// PkgAuditMatch is a ranking how confident the CVE-ID was deteted correctly
PkgAuditMatch = Confidence{100, PkgAuditMatchStr, 2}
// OvalMatch is a ranking how confident the CVE-ID was deteted correctly
OvalMatch = Confidence{100, OvalMatchStr, 0}
// RedHatAPIMatch ranking how confident the CVE-ID was deteted correctly
RedHatAPIMatch = Confidence{100, RedHatAPIStr, 0}
// DebianSecurityTrackerMatch ranking how confident the CVE-ID was deteted correctly
DebianSecurityTrackerMatch = Confidence{100, DebianSecurityTrackerMatchStr, 0}
// TrivyMatch ranking how confident the CVE-ID was deteted correctly
TrivyMatch = Confidence{100, TrivyMatchStr, 0}
// ChangelogExactMatch is a ranking how confident the CVE-ID was deteted correctly
ChangelogExactMatch = Confidence{95, ChangelogExactMatchStr, 3}
// ChangelogLenientMatch is a ranking how confident the CVE-ID was deteted correctly
ChangelogLenientMatch = Confidence{50, ChangelogLenientMatchStr, 4}
// GitHubMatch is a ranking how confident the CVE-ID was deteted correctly
GitHubMatch = Confidence{97, GitHubMatchStr, 2}
// WPVulnDBMatch is a ranking how confident the CVE-ID was deteted correctly
WPVulnDBMatch = Confidence{100, WPVulnDBMatchStr, 0}
)

File diff suppressed because it is too large Load Diff

View File

@@ -1,71 +0,0 @@
package models
// WordPressPackages has Core version, plugins and themes.
type WordPressPackages []WpPackage
// CoreVersion returns the core version of the installed WordPress
func (w WordPressPackages) CoreVersion() string {
for _, p := range w {
if p.Type == WPCore {
return p.Version
}
}
return ""
}
// Plugins returns a slice of plugins of the installed WordPress
func (w WordPressPackages) Plugins() (ps []WpPackage) {
for _, p := range w {
if p.Type == WPPlugin {
ps = append(ps, p)
}
}
return
}
// Themes returns a slice of themes of the installed WordPress
func (w WordPressPackages) Themes() (ps []WpPackage) {
for _, p := range w {
if p.Type == WPTheme {
ps = append(ps, p)
}
}
return
}
// Find searches by specified name
func (w WordPressPackages) Find(name string) (ps *WpPackage, found bool) {
for _, p := range w {
if p.Name == name {
return &p, true
}
}
return nil, false
}
const (
// WPCore is a type `core` in WPPackage struct
WPCore = "core"
// WPPlugin is a type `plugin` in WPPackage struct
WPPlugin = "plugin"
// WPTheme is a type `theme` in WPPackage struct
WPTheme = "theme"
// Inactive is a inactive status in WPPackage struct
Inactive = "inactive"
)
// WpPackage has a details of plugin and theme
type WpPackage struct {
Name string `json:"name,omitempty"`
Status string `json:"status,omitempty"` // active, inactive or must-use
Update string `json:"update,omitempty"` // available or none
Version string `json:"version,omitempty"`
Type string `json:"type,omitempty"` // core, plugin, theme
}
// WpPackageFixStatus is used in Vulninfo.WordPress
type WpPackageFixStatus struct {
Name string `json:"name,omitempty"`
FixedIn string `json:"fixedIn,omitempty"`
}

View File

@@ -1,73 +0,0 @@
package msf
import (
"fmt"
"net/http"
cnf "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/parnurzeal/gorequest"
"github.com/takuzoo3868/go-msfdb/db"
metasploitmodels "github.com/takuzoo3868/go-msfdb/models"
"golang.org/x/xerrors"
)
// FillWithMetasploit fills metasploit module information that has in module
func FillWithMetasploit(driver db.DB, r *models.ScanResult) (nMetasploitCve int, err error) {
if driver == nil {
return 0, nil
}
for cveID, vuln := range r.ScannedCves {
if cveID == "" {
continue
}
ms := driver.GetModuleByCveID(cveID)
if len(ms) == 0 {
continue
}
modules := ConvertToModels(ms)
vuln.Metasploits = modules
r.ScannedCves[cveID] = vuln
nMetasploitCve++
}
return nMetasploitCve, nil
}
// ConvertToModels converts gost model to vuls model
func ConvertToModels(ms []*metasploitmodels.Metasploit) (modules []models.Metasploit) {
for _, m := range ms {
var links []string
if 0 < len(m.References) {
for _, u := range m.References {
links = append(links, u.Link)
}
}
module := models.Metasploit{
Name: m.Name,
Title: m.Title,
Description: m.Description,
URLs: links,
}
modules = append(modules, module)
}
return modules
}
// CheckHTTPHealth do health check
func CheckHTTPHealth() error {
if !cnf.Conf.Metasploit.IsFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", cnf.Conf.Metasploit.URL)
var errs []error
var resp *http.Response
resp, _, errs = gorequest.New().Get(url).End()
// resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to connect to metasploit server. url: %s, errs: %w", url, errs)
}
return nil
}

View File

@@ -1,57 +0,0 @@
package oval
import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/kotakanbe/goval-dictionary/db"
)
// Alpine is the struct of Alpine Linux
type Alpine struct {
Base
}
// NewAlpine creates OVAL client for SUSE
func NewAlpine() Alpine {
return Alpine{
Base{
family: config.Alpine,
},
}
}
// FillWithOval returns scan result after updating CVE info by OVAL
func (o Alpine) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
var relatedDefs ovalResult
if config.Conf.OvalDict.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
return 0, err
}
} else {
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
}
}
for _, defPacks := range relatedDefs.entries {
o.update(r, defPacks)
}
return len(relatedDefs.entries), nil
}
func (o Alpine) update(r *models.ScanResult, defPacks defPacks) {
cveID := defPacks.def.Advisory.Cves[0].CveID
vinfo, ok := r.ScannedCves[cveID]
if !ok {
util.Log.Debugf("%s is newly detected by OVAL", cveID)
vinfo = models.VulnInfo{
CveID: cveID,
Confidences: []models.Confidence{models.OvalMatch},
}
}
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[cveID] = vinfo
}

View File

@@ -1,457 +0,0 @@
package oval
import (
"fmt"
"strings"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/kotakanbe/goval-dictionary/db"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
)
// DebianBase is the base struct of Debian and Ubuntu
type DebianBase struct {
Base
}
func (o DebianBase) update(r *models.ScanResult, defPacks defPacks) {
ovalContent := *o.convertToModel(&defPacks.def)
ovalContent.Type = models.NewCveContentType(o.family)
vinfo, ok := r.ScannedCves[defPacks.def.Debian.CveID]
if !ok {
util.Log.Debugf("%s is newly detected by OVAL", defPacks.def.Debian.CveID)
vinfo = models.VulnInfo{
CveID: defPacks.def.Debian.CveID,
Confidences: []models.Confidence{models.OvalMatch},
CveContents: models.NewCveContents(ovalContent),
}
} else {
cveContents := vinfo.CveContents
ctype := models.NewCveContentType(o.family)
if _, ok := vinfo.CveContents[ctype]; ok {
util.Log.Debugf("%s OVAL will be overwritten",
defPacks.def.Debian.CveID)
} else {
util.Log.Debugf("%s is also detected by OVAL",
defPacks.def.Debian.CveID)
cveContents = models.CveContents{}
}
if r.Family != config.Raspbian {
vinfo.Confidences.AppendIfMissing(models.OvalMatch)
} else {
if len(vinfo.Confidences) == 0 {
vinfo.Confidences.AppendIfMissing(models.OvalMatch)
}
}
cveContents[ctype] = ovalContent
vinfo.CveContents = cveContents
}
// uniq(vinfo.PackNames + defPacks.binpkgStat)
for _, pack := range vinfo.AffectedPackages {
defPacks.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: pack.NotFixedYet,
fixedIn: pack.FixedIn,
isSrcPack: false,
}
}
// Update package status of source packages.
// In the case of Debian based Linux, sometimes source package name is difined as affected package in OVAL.
// To display binary package name showed in apt-get, need to convert source name to binary name.
for binName := range defPacks.binpkgFixstat {
if srcPack, ok := r.SrcPackages.FindByBinName(binName); ok {
for _, p := range defPacks.def.AffectedPacks {
if p.Name == srcPack.Name {
defPacks.binpkgFixstat[binName] = fixStat{
notFixedYet: p.NotFixedYet,
fixedIn: p.Version,
isSrcPack: true,
srcPackName: srcPack.Name,
}
}
}
}
}
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[defPacks.def.Debian.CveID] = vinfo
}
func (o DebianBase) convertToModel(def *ovalmodels.Definition) *models.CveContent {
refs := []models.Reference{}
for _, r := range def.References {
refs = append(refs, models.Reference{
Link: r.RefURL,
Source: r.Source,
RefID: r.RefID,
})
}
return &models.CveContent{
CveID: def.Debian.CveID,
Title: def.Title,
Summary: def.Description,
Cvss2Severity: def.Advisory.Severity,
Cvss3Severity: def.Advisory.Severity,
References: refs,
}
}
// Debian is the interface for Debian OVAL
type Debian struct {
DebianBase
}
// NewDebian creates OVAL client for Debian
func NewDebian() Debian {
return Debian{
DebianBase{
Base{
family: config.Debian,
},
},
}
}
// FillWithOval returns scan result after updating CVE info by OVAL
func (o Debian) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
//Debian's uname gives both of kernel release(uname -r), version(kernel-image version)
linuxImage := "linux-image-" + r.RunningKernel.Release
// Add linux and set the version of running kernel to search OVAL.
if r.Container.ContainerID == "" {
newVer := ""
if p, ok := r.Packages[linuxImage]; ok {
newVer = p.NewVersion
}
r.Packages["linux"] = models.Package{
Name: "linux",
Version: r.RunningKernel.Version,
NewVersion: newVer,
}
}
var relatedDefs ovalResult
if config.Conf.OvalDict.IsFetchViaHTTP() {
if r.Family != config.Raspbian {
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
return 0, err
}
} else {
// OVAL does not support Package for Raspbian, so skip it.
result := r.RemoveRaspbianPackFromResult()
if relatedDefs, err = getDefsByPackNameViaHTTP(&result); err != nil {
return 0, err
}
}
} else {
if r.Family != config.Raspbian {
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
}
} else {
// OVAL does not support Package for Raspbian, so skip it.
result := r.RemoveRaspbianPackFromResult()
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, &result); err != nil {
return 0, err
}
}
}
delete(r.Packages, "linux")
for _, defPacks := range relatedDefs.entries {
// Remove "linux" added above for oval search
// linux is not a real package name (key of affected packages in OVAL)
if notFixedYet, ok := defPacks.binpkgFixstat["linux"]; ok {
defPacks.binpkgFixstat[linuxImage] = notFixedYet
delete(defPacks.binpkgFixstat, "linux")
for i, p := range defPacks.def.AffectedPacks {
if p.Name == "linux" {
p.Name = linuxImage
defPacks.def.AffectedPacks[i] = p
}
}
}
o.update(r, defPacks)
}
for _, vuln := range r.ScannedCves {
if cont, ok := vuln.CveContents[models.Debian]; ok {
cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
vuln.CveContents[models.Debian] = cont
}
}
return len(relatedDefs.entries), nil
}
// Ubuntu is the interface for Debian OVAL
type Ubuntu struct {
DebianBase
}
// NewUbuntu creates OVAL client for Debian
func NewUbuntu() Ubuntu {
return Ubuntu{
DebianBase{
Base{
family: config.Ubuntu,
},
},
}
}
// FillWithOval returns scan result after updating CVE info by OVAL
func (o Ubuntu) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
switch major(r.Release) {
case "14":
kernelNamesInOval := []string{
"linux-aws",
"linux-azure",
"linux-lts-xenial",
"linux-meta",
"linux-meta-aws",
"linux-meta-azure",
"linux-meta-lts-xenial",
"linux-signed",
"linux-signed-azure",
"linux-signed-lts-xenial",
"linux",
}
return o.fillWithOval(driver, r, kernelNamesInOval)
case "16":
kernelNamesInOval := []string{
"linux-aws",
"linux-aws-hwe",
"linux-azure",
"linux-euclid",
"linux-flo",
"linux-gcp",
"linux-gke",
"linux-goldfish",
"linux-hwe",
"linux-kvm",
"linux-mako",
"linux-meta",
"linux-meta-aws",
"linux-meta-aws-hwe",
"linux-meta-azure",
"linux-meta-gcp",
"linux-meta-hwe",
"linux-meta-kvm",
"linux-meta-oracle",
"linux-meta-raspi2",
"linux-meta-snapdragon",
"linux-oem",
"linux-oracle",
"linux-raspi2",
"linux-signed",
"linux-signed-azure",
"linux-signed-gcp",
"linux-signed-hwe",
"linux-signed-oracle",
"linux-snapdragon",
"linux",
}
return o.fillWithOval(driver, r, kernelNamesInOval)
case "18":
kernelNamesInOval := []string{
"linux-aws",
"linux-aws-5.0",
"linux-azure",
"linux-gcp",
"linux-gcp-5.3",
"linux-gke-4.15",
"linux-gke-5.0",
"linux-gke-5.3",
"linux-hwe",
"linux-kvm",
"linux-meta",
"linux-meta-aws",
"linux-meta-aws-5.0",
"linux-meta-azure",
"linux-meta-gcp",
"linux-meta-gcp-5.3",
"linux-meta-gke-4.15",
"linux-meta-gke-5.0",
"linux-meta-gke-5.3",
"linux-meta-hwe",
"linux-meta-kvm",
"linux-meta-oem",
"linux-meta-oem-osp1",
"linux-meta-oracle",
"linux-meta-oracle-5.0",
"linux-meta-oracle-5.3",
"linux-meta-raspi2",
"linux-meta-raspi2-5.3",
"linux-meta-snapdragon",
"linux-oem",
"linux-oem-osp1",
"linux-oracle",
"linux-oracle-5.0",
"linux-oracle-5.3",
"linux-raspi2",
"linux-raspi2-5.3",
"linux-signed",
"linux-signed-azure",
"linux-signed-gcp",
"linux-signed-gcp-5.3",
"linux-signed-gke-4.15",
"linux-signed-gke-5.0",
"linux-signed-gke-5.3",
"linux-signed-hwe",
"linux-signed-oem",
"linux-signed-oem-osp1",
"linux-signed-oracle",
"linux-signed-oracle-5.0",
"linux-signed-oracle-5.3",
"linux-snapdragon",
"linux",
}
return o.fillWithOval(driver, r, kernelNamesInOval)
case "20":
kernelNamesInOval := []string{
"linux-aws",
"linux-azure",
"linux-gcp",
"linux-kvm",
"linux-meta",
"linux-meta-aws",
"linux-meta-azure",
"linux-meta-gcp",
"linux-meta-kvm",
"linux-meta-oem-5.6",
"linux-meta-oracle",
"linux-meta-raspi",
"linux-meta-riscv",
"linux-oem-5.6",
"linux-oracle",
"linux-raspi",
"linux-raspi2",
"linux-riscv",
"linux-signed",
"linux-signed-azure",
"linux-signed-gcp",
"linux-signed-oem-5.6",
"linux-signed-oracle",
"linux",
}
return o.fillWithOval(driver, r, kernelNamesInOval)
}
return 0, fmt.Errorf("Ubuntu %s is not support for now", r.Release)
}
func (o Ubuntu) fillWithOval(driver db.DB, r *models.ScanResult, kernelNamesInOval []string) (nCVEs int, err error) {
linuxImage := "linux-image-" + r.RunningKernel.Release
runningKernelVersion := ""
kernelPkgInOVAL := ""
isOVALKernelPkgAdded := false
unusedKernels := []models.Package{}
copiedSourcePkgs := models.SrcPackages{}
if r.Container.ContainerID == "" {
if v, ok := r.Packages[linuxImage]; ok {
runningKernelVersion = v.Version
} else {
util.Log.Warnf("Unable to detect vulns of running kernel because the version of the runnning kernel is unknown. server: %s",
r.ServerName)
}
for _, n := range kernelNamesInOval {
if p, ok := r.Packages[n]; ok {
kernelPkgInOVAL = p.Name
break
}
}
// remove unused kernels from packages to prevent detecting vulns of unused kernel
for _, n := range kernelNamesInOval {
if v, ok := r.Packages[n]; ok {
unusedKernels = append(unusedKernels, v)
delete(r.Packages, n)
}
}
// Remove linux-* in order to detect only vulnerabilities in the running kernel.
for n := range r.Packages {
if n != kernelPkgInOVAL && strings.HasPrefix(n, "linux-") {
unusedKernels = append(unusedKernels, r.Packages[n])
delete(r.Packages, n)
}
}
for srcPackName, srcPack := range r.SrcPackages {
copiedSourcePkgs[srcPackName] = srcPack
targetBianryNames := []string{}
for _, n := range srcPack.BinaryNames {
if n == kernelPkgInOVAL || !strings.HasPrefix(n, "linux-") {
targetBianryNames = append(targetBianryNames, n)
}
}
srcPack.BinaryNames = targetBianryNames
r.SrcPackages[srcPackName] = srcPack
}
if kernelPkgInOVAL == "" {
util.Log.Warnf("The OVAL name of the running kernel image %+v is not found. So vulns of `linux` wll be detected. server: %s",
r.RunningKernel, r.ServerName)
kernelPkgInOVAL = "linux"
isOVALKernelPkgAdded = true
}
if runningKernelVersion != "" {
r.Packages[kernelPkgInOVAL] = models.Package{
Name: kernelPkgInOVAL,
Version: runningKernelVersion,
}
}
}
var relatedDefs ovalResult
if config.Conf.OvalDict.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
return 0, err
}
} else {
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
}
}
if isOVALKernelPkgAdded {
delete(r.Packages, kernelPkgInOVAL)
}
for _, p := range unusedKernels {
r.Packages[p.Name] = p
}
r.SrcPackages = copiedSourcePkgs
for _, defPacks := range relatedDefs.entries {
// Remove "linux" added above for searching oval
// "linux" is not a real package name (key of affected packages in OVAL)
if nfy, ok := defPacks.binpkgFixstat[kernelPkgInOVAL]; isOVALKernelPkgAdded && ok {
defPacks.binpkgFixstat[linuxImage] = nfy
delete(defPacks.binpkgFixstat, kernelPkgInOVAL)
for i, p := range defPacks.def.AffectedPacks {
if p.Name == kernelPkgInOVAL {
p.Name = linuxImage
defPacks.def.AffectedPacks[i] = p
}
}
}
o.update(r, defPacks)
}
for _, vuln := range r.ScannedCves {
if cont, ok := vuln.CveContents[models.Ubuntu]; ok {
cont.SourceLink = "http://people.ubuntu.com/~ubuntu-security/cve/" + cont.CveID
vuln.CveContents[models.Ubuntu] = cont
}
}
return len(relatedDefs.entries), nil
}

View File

@@ -1,66 +0,0 @@
package oval
import (
"reflect"
"testing"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
)
func TestPackNamesOfUpdateDebian(t *testing.T) {
var tests = []struct {
in models.ScanResult
defPacks defPacks
out models.ScanResult
}{
{
in: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2000-1000": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packA"},
{Name: "packC"},
},
},
},
},
defPacks: defPacks{
def: ovalmodels.Definition{
Debian: ovalmodels.Debian{
CveID: "CVE-2000-1000",
},
},
binpkgFixstat: map[string]fixStat{
"packB": {
notFixedYet: true,
fixedIn: "1.0.0",
},
},
},
out: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2000-1000": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packA"},
{Name: "packB", NotFixedYet: true, FixedIn: "1.0.0"},
{Name: "packC"},
},
},
},
},
},
}
util.Log = util.NewCustomLogger(config.ServerInfo{})
for i, tt := range tests {
Debian{}.update(&tt.in, tt.defPacks)
e := tt.out.ScannedCves["CVE-2000-1000"].AffectedPackages
a := tt.in.ScannedCves["CVE-2000-1000"].AffectedPackages
if !reflect.DeepEqual(a, e) {
t.Errorf("[%d] expected: %#v\n actual: %#v\n", i, e, a)
}
}
}

View File

@@ -1,99 +0,0 @@
package oval
import (
"encoding/json"
"fmt"
"net/http"
"time"
cnf "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/kotakanbe/goval-dictionary/db"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
)
// Client is the interface of OVAL client.
type Client interface {
CheckHTTPHealth() error
FillWithOval(db.DB, *models.ScanResult) (int, error)
// CheckIfOvalFetched checks if oval entries are in DB by family, release.
CheckIfOvalFetched(db.DB, string, string) (bool, error)
CheckIfOvalFresh(db.DB, string, string) (bool, error)
}
// Base is a base struct
type Base struct {
family string
}
// CheckHTTPHealth do health check
func (b Base) CheckHTTPHealth() error {
if !cnf.Conf.OvalDict.IsFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", cnf.Conf.OvalDict.URL)
var errs []error
var resp *http.Response
resp, _, errs = gorequest.New().Get(url).End()
// resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to request to OVAL server. url: %s, errs: %w",
url, errs)
}
return nil
}
// CheckIfOvalFetched checks if oval entries are in DB by family, release.
func (b Base) CheckIfOvalFetched(driver db.DB, osFamily, release string) (fetched bool, err error) {
if !cnf.Conf.OvalDict.IsFetchViaHTTP() {
count, err := driver.CountDefs(osFamily, release)
if err != nil {
return false, xerrors.Errorf("Failed to count OVAL defs: %s, %s, %w", osFamily, release, err)
}
return 0 < count, nil
}
url, _ := util.URLPathJoin(cnf.Conf.OvalDict.URL, "count", osFamily, release)
resp, body, errs := gorequest.New().Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %w", url, resp, errs)
}
count := 0
if err := json.Unmarshal([]byte(body), &count); err != nil {
return false, xerrors.Errorf("Failed to Unmarshall. body: %s, err: %w", body, err)
}
return 0 < count, nil
}
// CheckIfOvalFresh checks if oval entries are fresh enough
func (b Base) CheckIfOvalFresh(driver db.DB, osFamily, release string) (ok bool, err error) {
var lastModified time.Time
if !cnf.Conf.OvalDict.IsFetchViaHTTP() {
lastModified = driver.GetLastModified(osFamily, release)
} else {
url, _ := util.URLPathJoin(cnf.Conf.OvalDict.URL, "lastmodified", osFamily, release)
resp, body, errs := gorequest.New().Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %w", url, resp, errs)
}
if err := json.Unmarshal([]byte(body), &lastModified); err != nil {
return false, xerrors.Errorf("Failed to Unmarshall. body: %s, err: %w", body, err)
}
}
since := time.Now()
since = since.AddDate(0, 0, -3)
if lastModified.Before(since) {
util.Log.Warnf("OVAL for %s %s is old, last modified is %s. It's recommended to update OVAL to improve scanning accuracy. How to update OVAL database, see https://github.com/kotakanbe/goval-dictionary#usage",
osFamily, release, lastModified)
return false, nil
}
util.Log.Infof("OVAL is fresh: %s %s ", osFamily, release)
return true, nil
}

View File

@@ -1,306 +0,0 @@
package oval
import (
"fmt"
"strconv"
"strings"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/kotakanbe/goval-dictionary/db"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
)
// RedHatBase is the base struct for RedHat and CentOS
type RedHatBase struct {
Base
}
// FillWithOval returns scan result after updating CVE info by OVAL
func (o RedHatBase) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
var relatedDefs ovalResult
if config.Conf.OvalDict.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
return 0, err
}
} else {
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
}
}
for _, defPacks := range relatedDefs.entries {
nCVEs += o.update(r, defPacks)
}
for _, vuln := range r.ScannedCves {
switch models.NewCveContentType(o.family) {
case models.RedHat:
if cont, ok := vuln.CveContents[models.RedHat]; ok {
cont.SourceLink = "https://access.redhat.com/security/cve/" + cont.CveID
vuln.CveContents[models.RedHat] = cont
}
case models.Oracle:
if cont, ok := vuln.CveContents[models.Oracle]; ok {
cont.SourceLink = fmt.Sprintf("https://linux.oracle.com/cve/%s.html", cont.CveID)
vuln.CveContents[models.Oracle] = cont
}
}
}
return nCVEs, nil
}
var kernelRelatedPackNames = map[string]bool{
"kernel": true,
"kernel-aarch64": true,
"kernel-abi-whitelists": true,
"kernel-bootwrapper": true,
"kernel-debug": true,
"kernel-debug-devel": true,
"kernel-devel": true,
"kernel-doc": true,
"kernel-headers": true,
"kernel-kdump": true,
"kernel-kdump-devel": true,
"kernel-rt": true,
"kernel-rt-debug": true,
"kernel-rt-debug-devel": true,
"kernel-rt-debug-kvm": true,
"kernel-rt-devel": true,
"kernel-rt-doc": true,
"kernel-rt-kvm": true,
"kernel-rt-trace": true,
"kernel-rt-trace-devel": true,
"kernel-rt-trace-kvm": true,
"kernel-rt-virt": true,
"kernel-rt-virt-devel": true,
"kernel-tools": true,
"kernel-tools-libs": true,
"kernel-tools-libs-devel": true,
"perf": true,
"python-perf": true,
}
func (o RedHatBase) update(r *models.ScanResult, defPacks defPacks) (nCVEs int) {
ctype := models.NewCveContentType(o.family)
for _, cve := range defPacks.def.Advisory.Cves {
ovalContent := *o.convertToModel(cve.CveID, &defPacks.def)
vinfo, ok := r.ScannedCves[cve.CveID]
if !ok {
util.Log.Debugf("%s is newly detected by OVAL", cve.CveID)
vinfo = models.VulnInfo{
CveID: cve.CveID,
Confidences: models.Confidences{models.OvalMatch},
CveContents: models.NewCveContents(ovalContent),
}
nCVEs++
} else {
cveContents := vinfo.CveContents
if v, ok := vinfo.CveContents[ctype]; ok {
if v.LastModified.After(ovalContent.LastModified) {
util.Log.Debugf("%s, OvalID: %d ignored: ",
cve.CveID, defPacks.def.ID)
} else {
util.Log.Debugf("%s OVAL will be overwritten", cve.CveID)
}
} else {
util.Log.Debugf("%s also detected by OVAL", cve.CveID)
cveContents = models.CveContents{}
}
vinfo.Confidences.AppendIfMissing(models.OvalMatch)
cveContents[ctype] = ovalContent
vinfo.CveContents = cveContents
}
vinfo.DistroAdvisories.AppendIfMissing(
o.convertToDistroAdvisory(&defPacks.def))
// uniq(vinfo.PackNames + defPacks.actuallyAffectedPackNames)
for _, pack := range vinfo.AffectedPackages {
if stat, ok := defPacks.binpkgFixstat[pack.Name]; !ok {
defPacks.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: pack.NotFixedYet,
fixedIn: pack.FixedIn,
}
} else if stat.notFixedYet {
defPacks.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: true,
fixedIn: pack.FixedIn,
}
}
}
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[cve.CveID] = vinfo
}
return
}
func (o RedHatBase) convertToDistroAdvisory(def *ovalmodels.Definition) *models.DistroAdvisory {
advisoryID := def.Title
if (o.family == config.RedHat || o.family == config.CentOS) && len(advisoryID) > 0 {
ss := strings.Fields(def.Title)
advisoryID = strings.TrimSuffix(ss[0], ":")
}
return &models.DistroAdvisory{
AdvisoryID: advisoryID,
Severity: def.Advisory.Severity,
Issued: def.Advisory.Issued,
Updated: def.Advisory.Updated,
Description: def.Description,
}
}
func (o RedHatBase) convertToModel(cveID string, def *ovalmodels.Definition) *models.CveContent {
for _, cve := range def.Advisory.Cves {
if cve.CveID != cveID {
continue
}
var refs []models.Reference
for _, r := range def.References {
refs = append(refs, models.Reference{
Link: r.RefURL,
Source: r.Source,
RefID: r.RefID,
})
}
score2, vec2 := o.parseCvss2(cve.Cvss2)
score3, vec3 := o.parseCvss3(cve.Cvss3)
severity := def.Advisory.Severity
if cve.Impact != "" {
severity = cve.Impact
}
sev2, sev3 := "", ""
if score2 == 0 {
sev2 = severity
}
if score3 == 0 {
sev3 = severity
}
// CWE-ID in RedHat OVAL may have multiple cweIDs separated by space
cwes := strings.Fields(cve.Cwe)
return &models.CveContent{
Type: models.NewCveContentType(o.family),
CveID: cve.CveID,
Title: def.Title,
Summary: def.Description,
Cvss2Score: score2,
Cvss2Vector: vec2,
Cvss2Severity: sev2,
Cvss3Score: score3,
Cvss3Vector: vec3,
Cvss3Severity: sev3,
References: refs,
CweIDs: cwes,
Published: def.Advisory.Issued,
LastModified: def.Advisory.Updated,
}
}
return nil
}
// ParseCvss2 divide CVSSv2 string into score and vector
// 5/AV:N/AC:L/Au:N/C:N/I:N/A:P
func (o RedHatBase) parseCvss2(scoreVector string) (score float64, vector string) {
var err error
ss := strings.Split(scoreVector, "/")
if 1 < len(ss) {
if score, err = strconv.ParseFloat(ss[0], 64); err != nil {
return 0, ""
}
return score, strings.Join(ss[1:], "/")
}
return 0, ""
}
// ParseCvss3 divide CVSSv3 string into score and vector
// 5.6/CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
func (o RedHatBase) parseCvss3(scoreVector string) (score float64, vector string) {
var err error
for _, s := range []string{
"/CVSS:3.0/",
"/CVSS:3.1/",
} {
ss := strings.Split(scoreVector, s)
if 1 < len(ss) {
if score, err = strconv.ParseFloat(ss[0], 64); err != nil {
return 0, ""
}
return score, strings.TrimPrefix(s, "/") + ss[1]
}
}
return 0, ""
}
// RedHat is the interface for RedhatBase OVAL
type RedHat struct {
RedHatBase
}
// NewRedhat creates OVAL client for Redhat
func NewRedhat() RedHat {
return RedHat{
RedHatBase{
Base{
family: config.RedHat,
},
},
}
}
// CentOS is the interface for CentOS OVAL
type CentOS struct {
RedHatBase
}
// NewCentOS creates OVAL client for CentOS
func NewCentOS() CentOS {
return CentOS{
RedHatBase{
Base{
family: config.CentOS,
},
},
}
}
// Oracle is the interface for Oracle OVAL
type Oracle struct {
RedHatBase
}
// NewOracle creates OVAL client for Oracle
func NewOracle() Oracle {
return Oracle{
RedHatBase{
Base{
family: config.Oracle,
},
},
}
}
// Amazon is the interface for RedhatBase OVAL
type Amazon struct {
// Base
RedHatBase
}
// NewAmazon creates OVAL client for Amazon Linux
func NewAmazon() Amazon {
return Amazon{
RedHatBase{
Base{
family: config.Amazon,
},
},
}
}

View File

@@ -1,142 +0,0 @@
package oval
import (
"reflect"
"testing"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
)
func TestParseCvss2(t *testing.T) {
type out struct {
score float64
vector string
}
var tests = []struct {
in string
out out
}{
{
in: "5/AV:N/AC:L/Au:N/C:N/I:N/A:P",
out: out{
score: 5.0,
vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
},
},
{
in: "",
out: out{
score: 0,
vector: "",
},
},
}
for _, tt := range tests {
s, v := RedHatBase{}.parseCvss2(tt.in)
if s != tt.out.score || v != tt.out.vector {
t.Errorf("\nexpected: %f, %s\n actual: %f, %s",
tt.out.score, tt.out.vector, s, v)
}
}
}
func TestParseCvss3(t *testing.T) {
type out struct {
score float64
vector string
}
var tests = []struct {
in string
out out
}{
{
in: "5.6/CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
out: out{
score: 5.6,
vector: "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
},
},
{
in: "6.1/CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
out: out{
score: 6.1,
vector: "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
},
},
{
in: "",
out: out{
score: 0,
vector: "",
},
},
}
for _, tt := range tests {
s, v := RedHatBase{}.parseCvss3(tt.in)
if s != tt.out.score || v != tt.out.vector {
t.Errorf("\nexpected: %f, %s\n actual: %f, %s",
tt.out.score, tt.out.vector, s, v)
}
}
}
func TestPackNamesOfUpdate(t *testing.T) {
var tests = []struct {
in models.ScanResult
defPacks defPacks
out models.ScanResult
}{
{
in: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2000-1000": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packA"},
{Name: "packB", NotFixedYet: false},
},
},
},
},
defPacks: defPacks{
def: ovalmodels.Definition{
Advisory: ovalmodels.Advisory{
Cves: []ovalmodels.Cve{
{
CveID: "CVE-2000-1000",
},
},
},
},
binpkgFixstat: map[string]fixStat{
"packB": {
notFixedYet: true,
fixedIn: "1.0.0",
},
},
},
out: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2000-1000": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packA"},
{Name: "packB", NotFixedYet: true},
},
},
},
},
},
}
util.Log = util.NewCustomLogger(config.ServerInfo{})
for i, tt := range tests {
RedHat{}.update(&tt.in, tt.defPacks)
e := tt.out.ScannedCves["CVE-2000-1000"].AffectedPackages
a := tt.in.ScannedCves["CVE-2000-1000"].AffectedPackages
if !reflect.DeepEqual(a, e) {
t.Errorf("[%d] expected: %v\n actual: %v\n", i, e, a)
}
}
}

View File

@@ -1,104 +0,0 @@
package oval
import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/kotakanbe/goval-dictionary/db"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
)
// SUSE is the struct of SUSE Linux
type SUSE struct {
Base
}
// NewSUSE creates OVAL client for SUSE
func NewSUSE() SUSE {
// TODO implement other family
return SUSE{
Base{
family: config.SUSEEnterpriseServer,
},
}
}
// FillWithOval returns scan result after updating CVE info by OVAL
func (o SUSE) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
var relatedDefs ovalResult
if config.Conf.OvalDict.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
return 0, err
}
} else {
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
}
}
for _, defPacks := range relatedDefs.entries {
o.update(r, defPacks)
}
for _, vuln := range r.ScannedCves {
if cont, ok := vuln.CveContents[models.SUSE]; ok {
cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
vuln.CveContents[models.SUSE] = cont
}
}
return len(relatedDefs.entries), nil
}
func (o SUSE) update(r *models.ScanResult, defPacks defPacks) {
ovalContent := *o.convertToModel(&defPacks.def)
ovalContent.Type = models.NewCveContentType(o.family)
vinfo, ok := r.ScannedCves[defPacks.def.Title]
if !ok {
util.Log.Debugf("%s is newly detected by OVAL", defPacks.def.Title)
vinfo = models.VulnInfo{
CveID: defPacks.def.Title,
Confidences: models.Confidences{models.OvalMatch},
CveContents: models.NewCveContents(ovalContent),
}
} else {
cveContents := vinfo.CveContents
ctype := models.NewCveContentType(o.family)
if _, ok := vinfo.CveContents[ctype]; ok {
util.Log.Debugf("%s OVAL will be overwritten", defPacks.def.Title)
} else {
util.Log.Debugf("%s is also detected by OVAL", defPacks.def.Title)
cveContents = models.CveContents{}
}
vinfo.Confidences.AppendIfMissing(models.OvalMatch)
cveContents[ctype] = ovalContent
vinfo.CveContents = cveContents
}
// uniq(vinfo.PackNames + defPacks.actuallyAffectedPackNames)
for _, pack := range vinfo.AffectedPackages {
defPacks.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: pack.NotFixedYet,
fixedIn: pack.FixedIn,
}
}
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[defPacks.def.Title] = vinfo
}
func (o SUSE) convertToModel(def *ovalmodels.Definition) *models.CveContent {
refs := []models.Reference{}
for _, r := range def.References {
refs = append(refs, models.Reference{
Link: r.RefURL,
Source: r.Source,
RefID: r.RefID,
})
}
return &models.CveContent{
CveID: def.Title,
Title: def.Title,
Summary: def.Description,
References: refs,
}
}

View File

@@ -1,406 +0,0 @@
package oval
import (
"encoding/json"
"net/http"
"regexp"
"strings"
"time"
"github.com/cenkalti/backoff"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
apkver "github.com/knqyf263/go-apk-version"
debver "github.com/knqyf263/go-deb-version"
rpmver "github.com/knqyf263/go-rpm-version"
"github.com/kotakanbe/goval-dictionary/db"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
)
type ovalResult struct {
entries []defPacks
}
type defPacks struct {
def ovalmodels.Definition
// BinaryPackageName : NotFixedYet
binpkgFixstat map[string]fixStat
}
type fixStat struct {
notFixedYet bool
fixedIn string
isSrcPack bool
srcPackName string
}
func (e defPacks) toPackStatuses() (ps models.PackageFixStatuses) {
for name, stat := range e.binpkgFixstat {
ps = append(ps, models.PackageFixStatus{
Name: name,
NotFixedYet: stat.notFixedYet,
FixedIn: stat.fixedIn,
})
}
return
}
func (e *ovalResult) upsert(def ovalmodels.Definition, packName string, fstat fixStat) (upserted bool) {
// alpine's entry is empty since Alpine secdb is not OVAL format
if def.DefinitionID != "" {
for i, entry := range e.entries {
if entry.def.DefinitionID == def.DefinitionID {
e.entries[i].binpkgFixstat[packName] = fstat
return true
}
}
}
e.entries = append(e.entries, defPacks{
def: def,
binpkgFixstat: map[string]fixStat{
packName: fstat,
},
})
return false
}
type request struct {
packName string
versionRelease string
newVersionRelease string
arch string
binaryPackNames []string
isSrcPack bool
}
type response struct {
request request
defs []ovalmodels.Definition
}
// getDefsByPackNameViaHTTP fetches OVAL information via HTTP
func getDefsByPackNameViaHTTP(r *models.ScanResult) (
relatedDefs ovalResult, err error) {
nReq := len(r.Packages) + len(r.SrcPackages)
reqChan := make(chan request, nReq)
resChan := make(chan response, nReq)
errChan := make(chan error, nReq)
defer close(reqChan)
defer close(resChan)
defer close(errChan)
go func() {
for _, pack := range r.Packages {
reqChan <- request{
packName: pack.Name,
versionRelease: pack.FormatVer(),
newVersionRelease: pack.FormatVer(),
isSrcPack: false,
arch: pack.Arch,
}
}
for _, pack := range r.SrcPackages {
reqChan <- request{
packName: pack.Name,
binaryPackNames: pack.BinaryNames,
versionRelease: pack.Version,
isSrcPack: true,
// arch: pack.Arch,
}
}
}()
concurrency := 10
tasks := util.GenWorkers(concurrency)
for i := 0; i < nReq; i++ {
tasks <- func() {
select {
case req := <-reqChan:
url, err := util.URLPathJoin(
config.Conf.OvalDict.URL,
"packs",
r.Family,
r.Release,
req.packName,
)
if err != nil {
errChan <- err
} else {
util.Log.Debugf("HTTP Request to %s", url)
httpGet(url, req, resChan, errChan)
}
}
}
}
timeout := time.After(2 * 60 * time.Second)
var errs []error
for i := 0; i < nReq; i++ {
select {
case res := <-resChan:
for _, def := range res.defs {
affected, notFixedYet, fixedIn := isOvalDefAffected(def, res.request, r.Family, r.RunningKernel)
if !affected {
continue
}
if res.request.isSrcPack {
for _, n := range res.request.binaryPackNames {
fs := fixStat{
srcPackName: res.request.packName,
isSrcPack: true,
notFixedYet: notFixedYet,
fixedIn: fixedIn,
}
relatedDefs.upsert(def, n, fs)
}
} else {
fs := fixStat{
notFixedYet: notFixedYet,
fixedIn: fixedIn,
}
relatedDefs.upsert(def, res.request.packName, fs)
}
}
case err := <-errChan:
errs = append(errs, err)
case <-timeout:
return relatedDefs, xerrors.New("Timeout Fetching OVAL")
}
}
if len(errs) != 0 {
return relatedDefs, xerrors.Errorf("Failed to fetch OVAL. err: %w", errs)
}
return
}
func httpGet(url string, req request, resChan chan<- response, errChan chan<- error) {
var body string
var errs []error
var resp *http.Response
count, retryMax := 0, 3
f := func() (err error) {
// resp, body, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
resp, body, errs = gorequest.New().Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
count++
if count == retryMax {
return nil
}
return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %w", url, resp, errs)
}
return nil
}
notify := func(err error, t time.Duration) {
util.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %s", t, err)
}
err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify)
if err != nil {
errChan <- xerrors.Errorf("HTTP Error %w", err)
return
}
if count == retryMax {
errChan <- xerrors.New("HRetry count exceeded")
return
}
defs := []ovalmodels.Definition{}
if err := json.Unmarshal([]byte(body), &defs); err != nil {
errChan <- xerrors.Errorf("Failed to Unmarshall. body: %s, err: %w", body, err)
return
}
resChan <- response{
request: req,
defs: defs,
}
}
func getDefsByPackNameFromOvalDB(driver db.DB, r *models.ScanResult) (relatedDefs ovalResult, err error) {
requests := []request{}
for _, pack := range r.Packages {
requests = append(requests, request{
packName: pack.Name,
versionRelease: pack.FormatVer(),
newVersionRelease: pack.FormatNewVer(),
arch: pack.Arch,
isSrcPack: false,
})
}
for _, pack := range r.SrcPackages {
requests = append(requests, request{
packName: pack.Name,
binaryPackNames: pack.BinaryNames,
versionRelease: pack.Version,
arch: pack.Arch,
isSrcPack: true,
})
}
for _, req := range requests {
definitions, err := driver.GetByPackName(r.Family, r.Release, req.packName, req.arch)
if err != nil {
return relatedDefs, xerrors.Errorf("Failed to get %s OVAL info by package: %#v, err: %w", r.Family, req, err)
}
for _, def := range definitions {
affected, notFixedYet, fixedIn := isOvalDefAffected(def, req, r.Family, r.RunningKernel)
if !affected {
continue
}
if req.isSrcPack {
for _, binName := range req.binaryPackNames {
fs := fixStat{
notFixedYet: false,
isSrcPack: true,
fixedIn: fixedIn,
srcPackName: req.packName,
}
relatedDefs.upsert(def, binName, fs)
}
} else {
fs := fixStat{
notFixedYet: notFixedYet,
fixedIn: fixedIn,
}
relatedDefs.upsert(def, req.packName, fs)
}
}
}
return
}
func major(version string) string {
ss := strings.SplitN(version, ":", 2)
ver := ""
if len(ss) == 1 {
ver = ss[0]
} else {
ver = ss[1]
}
return ver[0:strings.Index(ver, ".")]
}
func isOvalDefAffected(def ovalmodels.Definition, req request, family string, running models.Kernel) (affected, notFixedYet bool, fixedIn string) {
for _, ovalPack := range def.AffectedPacks {
if req.packName != ovalPack.Name {
continue
}
if running.Release != "" {
switch family {
case config.RedHat, config.CentOS:
// For kernel related packages, ignore OVAL information with different major versions
if _, ok := kernelRelatedPackNames[ovalPack.Name]; ok {
if major(ovalPack.Version) != major(running.Release) {
continue
}
}
}
}
if ovalPack.NotFixedYet {
return true, true, ovalPack.Version
}
// Compare between the installed version vs the version in OVAL
less, err := lessThan(family, req.versionRelease, ovalPack)
if err != nil {
util.Log.Debugf("Failed to parse versions: %s, Ver: %#v, OVAL: %#v, DefID: %s",
err, req.versionRelease, ovalPack, def.DefinitionID)
return false, false, ovalPack.Version
}
if less {
if req.isSrcPack {
// Unable to judge whether fixed or not-fixed of src package(Ubuntu, Debian)
return true, false, ovalPack.Version
}
// If the version of installed is less than in OVAL
switch family {
case config.RedHat,
config.Amazon,
config.SUSEEnterpriseServer,
config.Debian,
config.Ubuntu,
config.Raspbian:
// Use fixed state in OVAL for these distros.
return true, false, ovalPack.Version
}
// But CentOS can't judge whether fixed or unfixed.
// Because fixed state in RHEL's OVAL is different.
// So, it have to be judged version comparison.
// `offline` or `fast` scan mode can't get a updatable version.
// In these mode, the blow field was set empty.
// Vuls can not judge fixed or unfixed.
if req.newVersionRelease == "" {
return true, false, ovalPack.Version
}
// compare version: newVer vs oval
less, err := lessThan(family, req.newVersionRelease, ovalPack)
if err != nil {
util.Log.Debugf("Failed to parse versions: %s, NewVer: %#v, OVAL: %#v, DefID: %s",
err, req.newVersionRelease, ovalPack, def.DefinitionID)
return false, false, ovalPack.Version
}
return true, less, ovalPack.Version
}
}
return false, false, ""
}
var centosVerPattern = regexp.MustCompile(`\.[es]l(\d+)(?:_\d+)?(?:\.centos)?`)
var esVerPattern = regexp.MustCompile(`\.el(\d+)(?:_\d+)?`)
func lessThan(family, newVer string, packInOVAL ovalmodels.Package) (bool, error) {
switch family {
case config.Debian,
config.Ubuntu,
config.Raspbian:
vera, err := debver.NewVersion(newVer)
if err != nil {
return false, err
}
verb, err := debver.NewVersion(packInOVAL.Version)
if err != nil {
return false, err
}
return vera.LessThan(verb), nil
case config.Alpine:
vera, err := apkver.NewVersion(newVer)
if err != nil {
return false, err
}
verb, err := apkver.NewVersion(packInOVAL.Version)
if err != nil {
return false, err
}
return vera.LessThan(verb), nil
case config.Oracle,
config.SUSEEnterpriseServer,
config.Amazon:
vera := rpmver.NewVersion(newVer)
verb := rpmver.NewVersion(packInOVAL.Version)
return vera.LessThan(verb), nil
case config.RedHat,
config.CentOS:
vera := rpmver.NewVersion(centosVerPattern.ReplaceAllString(newVer, ".el$1"))
verb := rpmver.NewVersion(esVerPattern.ReplaceAllString(packInOVAL.Version, ".el$1"))
return vera.LessThan(verb), nil
default:
util.Log.Errorf("Not implemented yet: %s", family)
}
return false, xerrors.Errorf("Package version comparison not supported: %s", family)
}

File diff suppressed because it is too large Load Diff

22
pkg/cmd/config/config.go Normal file
View File

@@ -0,0 +1,22 @@
package config
import (
"github.com/MakeNowJust/heredoc"
"github.com/spf13/cobra"
configInitCmd "github.com/future-architect/vuls/pkg/cmd/config/init"
)
func NewCmdConfig() *cobra.Command {
cmd := &cobra.Command{
Use: "config <subcommand>",
Short: "Vuls Config Operation",
Example: heredoc.Doc(`
$ vuls config init > config.json
`),
}
cmd.AddCommand(configInitCmd.NewCmdInit())
return cmd
}

Some files were not shown because too many files have changed in this diff Show More