Compare commits
329 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f047a6fe0c | ||
|
|
7f15a86d6a | ||
|
|
da1e515253 | ||
|
|
591786fde6 | ||
|
|
47e6ea249d | ||
|
|
4a72295de7 | ||
|
|
9ed5f2cac5 | ||
|
|
3e67f04fe4 | ||
|
|
b9416ae062 | ||
|
|
b4e49e093e | ||
|
|
020f6ac609 | ||
|
|
7e71cbdd46 | ||
|
|
1003f62212 | ||
|
|
9b18e1f9f0 | ||
|
|
24f790f474 | ||
|
|
fb8749fc5e | ||
|
|
96c3592db1 | ||
|
|
d65421cf46 | ||
|
|
c52ba448cd | ||
|
|
21adce463b | ||
|
|
f24240bf90 | ||
|
|
ff83cadd6e | ||
|
|
e8c09282d9 | ||
|
|
5f4d68cde4 | ||
|
|
9077a83ea8 | ||
|
|
543dc99ecd | ||
|
|
f0b3a8b1db | ||
|
|
0b9ec05181 | ||
|
|
0bf12412d6 | ||
|
|
0ea4d58c63 | ||
|
|
5755b00576 | ||
|
|
1c8e074c9d | ||
|
|
0e0e5ce4be | ||
|
|
23dfe53885 | ||
|
|
8e6351a9e4 | ||
|
|
3086e2760f | ||
|
|
b8db2e0b74 | ||
|
|
43b46cb324 | ||
|
|
d0559c7719 | ||
|
|
231c63cf62 | ||
|
|
2a9aebe059 | ||
|
|
4e535d792f | ||
|
|
4b487503d4 | ||
|
|
0095c40e69 | ||
|
|
82c1abfd3a | ||
|
|
40988401bd | ||
|
|
e8e3f4d138 | ||
|
|
7eb77f5b51 | ||
|
|
e115235299 | ||
|
|
151d4b2d30 | ||
|
|
e553f8b4c5 | ||
|
|
47652ef0fb | ||
|
|
ab0e950800 | ||
|
|
a7b0ce1c85 | ||
|
|
dc9c0edece | ||
|
|
17ae386d1e | ||
|
|
2d369d0cfe | ||
|
|
c36e645d9b | ||
|
|
40039c07e2 | ||
|
|
a692cec0ef | ||
|
|
e7ca491a94 | ||
|
|
23f3e2fc11 | ||
|
|
27b3e17b79 | ||
|
|
740781af56 | ||
|
|
36c9c229b8 | ||
|
|
183fdcbdef | ||
|
|
a2a697900a | ||
|
|
6fef4db8a0 | ||
|
|
e879ff1e9e | ||
|
|
9bfe0627ae | ||
|
|
0179f4299a | ||
|
|
56017e57a0 | ||
|
|
cda91e0906 | ||
|
|
5d47adb5c9 | ||
|
|
54e73c2f54 | ||
|
|
2d075079f1 | ||
|
|
2a8ee4b22b | ||
|
|
1ec31d7be9 | ||
|
|
02286b0c59 | ||
|
|
1d0c5dea9f | ||
|
|
1c4a12c4b7 | ||
|
|
3f2ac45d71 | ||
|
|
518f4dc039 | ||
|
|
2cdeef4ffe | ||
|
|
03579126fd | ||
|
|
e3c27e1817 | ||
|
|
aeaf308679 | ||
|
|
f5e47bea40 | ||
|
|
50cf13a7f2 | ||
|
|
abd8041772 | ||
|
|
847c6438e7 | ||
|
|
ef8309df27 | ||
|
|
0dff6cf983 | ||
|
|
4c04acbd9e | ||
|
|
1c4f231572 | ||
|
|
51b8e169d2 | ||
|
|
b4611ae9b7 | ||
|
|
cd6722017b | ||
|
|
290edffccf | ||
|
|
64a6222bf9 | ||
|
|
adb686b7c9 | ||
|
|
d4af341b0f | ||
|
|
fea7e93c8d | ||
|
|
8b6b8d0f2e | ||
|
|
4dcbd865cc | ||
|
|
39b19444fe | ||
|
|
644d5a5462 | ||
|
|
8e18451e3f | ||
|
|
3dbdd01f97 | ||
|
|
a89079c005 | ||
|
|
a8c0926b4f | ||
|
|
dd2959a31b | ||
|
|
51099f42c3 | ||
|
|
63f170cc7a | ||
|
|
3c1489e588 | ||
|
|
e4f1e03f62 | ||
|
|
83d48ec990 | ||
|
|
b20d2b2684 | ||
|
|
2b918c70ae | ||
|
|
1100c133ba | ||
|
|
88899f0e89 | ||
|
|
59dc0059bc | ||
|
|
986fb304c0 | ||
|
|
d6435d2885 | ||
|
|
affb456499 | ||
|
|
705ed0a0ac | ||
|
|
dfffe5b508 | ||
|
|
fca102edba | ||
|
|
554b6345a2 | ||
|
|
aa954dc84c | ||
|
|
b5506a1368 | ||
|
|
0b55f94828 | ||
|
|
a67052f48c | ||
|
|
6eff6a9329 | ||
|
|
69d32d4511 | ||
|
|
d7a613b710 | ||
|
|
669c019287 | ||
|
|
fcc4901a10 | ||
|
|
4359503484 | ||
|
|
b13f93a2d3 | ||
|
|
8405e0fad6 | ||
|
|
aceb3f1826 | ||
|
|
a206675f3e | ||
|
|
f4253d74ae | ||
|
|
aaea15e516 | ||
|
|
83d1f80959 | ||
|
|
a33cff8f13 | ||
|
|
8679759f60 | ||
|
|
53deaee3d7 | ||
|
|
5a14a58fe4 | ||
|
|
fb1fbf8f95 | ||
|
|
cfbf779f9b | ||
|
|
d576b6c6c1 | ||
|
|
514eb71482 | ||
|
|
43ed904db1 | ||
|
|
0a440ca629 | ||
|
|
eff1dbf95b | ||
|
|
9a32a94806 | ||
|
|
2534098509 | ||
|
|
9497365758 | ||
|
|
101c44c9c0 | ||
|
|
ffd745c004 | ||
|
|
5fea4eaef8 | ||
|
|
1f610043cf | ||
|
|
3f8de02683 | ||
|
|
d02535d053 | ||
|
|
75fceff5f7 | ||
|
|
ebd3834a35 | ||
|
|
93059b74c3 | ||
|
|
2fc3462d35 | ||
|
|
f78dab50cb | ||
|
|
edb324c3d9 | ||
|
|
83bcca6e66 | ||
|
|
a124518d78 | ||
|
|
94bf630e29 | ||
|
|
31bb33fd90 | ||
|
|
4b680b9960 | ||
|
|
8a8ab8cb18 | ||
|
|
8146f5fd1b | ||
|
|
425c585e47 | ||
|
|
4f1578b2d6 | ||
|
|
7969b343b0 | ||
|
|
58cf1f4c8e | ||
|
|
a5b87af862 | ||
|
|
a0e592b934 | ||
|
|
7eccc538bb | ||
|
|
59daa8570a | ||
|
|
3f52d318bc | ||
|
|
11a7a0c934 | ||
|
|
89f49b0e29 | ||
|
|
72457cbf8e | ||
|
|
c11ba27509 | ||
|
|
8a611f9ba6 | ||
|
|
4a73875e4d | ||
|
|
d9d5e612ff | ||
|
|
4d8599e4fc | ||
|
|
59c7061d29 | ||
|
|
996557c667 | ||
|
|
519fb19a77 | ||
|
|
36456cb151 | ||
|
|
4ae87cc36c | ||
|
|
b37df89fb1 | ||
|
|
d18e7a751d | ||
|
|
8d5ea98e50 | ||
|
|
835dc08049 | ||
|
|
62c9409fe9 | ||
|
|
2374f578ed | ||
|
|
34e2f033d8 | ||
|
|
420825cacc | ||
|
|
466ec93d8e | ||
|
|
3f5bb6ab29 | ||
|
|
ebe5f858c8 | ||
|
|
9dd025437b | ||
|
|
c0ebac305a | ||
|
|
1f23ab7ba4 | ||
|
|
ea3b63998d | ||
|
|
3093426458 | ||
|
|
37716feac7 | ||
|
|
56b12c38d2 | ||
|
|
749ead5d4a | ||
|
|
3be50ab8da | ||
|
|
649f4a6991 | ||
|
|
0ff7641471 | ||
|
|
1679bfae20 | ||
|
|
45aa364436 | ||
|
|
778516c4d9 | ||
|
|
464d523c42 | ||
|
|
0f6a1987d4 | ||
|
|
20c6247ce5 | ||
|
|
a10dd67e0f | ||
|
|
5729ad6026 | ||
|
|
9aa0d87a21 | ||
|
|
fe3f1b9924 | ||
|
|
00e52a88fa | ||
|
|
5811dffe7a | ||
|
|
7278982af4 | ||
|
|
c17b4154ec | ||
|
|
d6e74cce08 | ||
|
|
3f80749241 | ||
|
|
7f72b6ac69 | ||
|
|
03e7b90b9f | ||
|
|
7936b3533b | ||
|
|
bd7e61d7cc | ||
|
|
69214e0c22 | ||
|
|
45bff26558 | ||
|
|
b2e429ccc6 | ||
|
|
76363c227b | ||
|
|
d5a3e5c2c5 | ||
|
|
2b02807ef0 | ||
|
|
be659ae094 | ||
|
|
b2c105adbc | ||
|
|
c61f462948 | ||
|
|
3ffed18e02 | ||
|
|
f54e7257d1 | ||
|
|
cc13b6a27c | ||
|
|
8877db1979 | ||
|
|
af58122c91 | ||
|
|
b7ca5e5590 | ||
|
|
69b6d875e6 | ||
|
|
1fbd516b83 | ||
|
|
dec5d3b165 | ||
|
|
d5e2040cef | ||
|
|
4326befdec | ||
|
|
3d4a5d9917 | ||
|
|
d770034788 | ||
|
|
a977533c78 | ||
|
|
c5e13dd5e4 | ||
|
|
a8040fe4d2 | ||
|
|
9e066008c3 | ||
|
|
22c6601526 | ||
|
|
425464fd76 | ||
|
|
ccb0751ffd | ||
|
|
f832de81b7 | ||
|
|
8a37de0686 | ||
|
|
836e4704f8 | ||
|
|
3e5390309c | ||
|
|
f8c0b38716 | ||
|
|
65e6070e5f | ||
|
|
7b78ebbc42 | ||
|
|
03c3189c02 | ||
|
|
4a34dfe0e9 | ||
|
|
4cf9a723fe | ||
|
|
bd1b135db3 | ||
|
|
8c3b305149 | ||
|
|
a3719038b8 | ||
|
|
c68a261c0b | ||
|
|
75fea79ac1 | ||
|
|
eb9f9680ec | ||
|
|
3634afdb81 | ||
|
|
77b5df896a | ||
|
|
b81f64058c | ||
|
|
a8a90d7c63 | ||
|
|
17bb575002 | ||
|
|
abcea1a14d | ||
|
|
10942f7c08 | ||
|
|
87ee829e80 | ||
|
|
fcc2c1e4c7 | ||
|
|
269095d034 | ||
|
|
40492ee00a | ||
|
|
64cdd5aedc | ||
|
|
3bb650cb77 | ||
|
|
774544c975 | ||
|
|
299805a726 | ||
|
|
276363e793 | ||
|
|
e750bd53fc | ||
|
|
98fee7b5d2 | ||
|
|
53aaea9fe2 | ||
|
|
824fbb6368 | ||
|
|
80566b91ab | ||
|
|
533d05a1b5 | ||
|
|
6a1fc4fade | ||
|
|
9008d0ddf0 | ||
|
|
583f4577bc | ||
|
|
e5716d5092 | ||
|
|
7192ae1287 | ||
|
|
99c65eff48 | ||
|
|
91df593566 | ||
|
|
07aeaeb989 | ||
|
|
cfeecdacd0 | ||
|
|
564dfa8b62 | ||
|
|
75dd6f2010 | ||
|
|
e26fd0b759 | ||
|
|
d630680a51 | ||
|
|
1723c3f6a0 | ||
|
|
53dd90302e | ||
|
|
5c6e06b05e | ||
|
|
cf6fb0c8a5 | ||
|
|
e0e71b2eae | ||
|
|
53f4a29fb1 |
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: kotakanbe
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
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.)
|
||||
|
||||
9
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
Normal file
9
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
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!
|
||||
-->
|
||||
10
.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
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.
|
||||
-->
|
||||
7
.github/ISSUE_TEMPLATE/VULSREPO.md
vendored
Normal file
7
.github/ISSUE_TEMPLATE/VULSREPO.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: Vuls Repo
|
||||
labels: vulsrepo
|
||||
about: If something isn't working as expected.
|
||||
---
|
||||
|
||||
|
||||
67
.github/workflows/codeql-analysis.yml
vendored
Normal file
67
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '32 20 * * 0'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'go' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
45
.github/workflows/docker-publish.yml
vendored
Normal file
45
.github/workflows/docker-publish.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
name: Publish Docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
with:
|
||||
images: vuls/vuls
|
||||
tags: |
|
||||
type=ref,event=tag
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: true
|
||||
tags: |
|
||||
vuls/vuls:latest
|
||||
${{ steps.meta.outputs.tags }}
|
||||
secrets: |
|
||||
"github_token=${{ secrets.GITHUB_TOKEN }}"
|
||||
29
.github/workflows/golangci.yml
vendored
Normal file
29
.github/workflows/golangci.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
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@v2
|
||||
with:
|
||||
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
|
||||
version: v1.42
|
||||
args: --timeout=10m
|
||||
|
||||
# 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
|
||||
31
.github/workflows/goreleaser.yml
vendored
Normal file
31
.github/workflows/goreleaser.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
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.16
|
||||
-
|
||||
name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
21
.github/workflows/test.yml
vendored
Normal file
21
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: Test
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16.x
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Test
|
||||
run: make test
|
||||
22
.github/workflows/tidy.yml
vendored
Normal file
22
.github/workflows/tidy.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
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.16.x
|
||||
14
.gitignore
vendored
14
.gitignore
vendored
@@ -1,7 +1,6 @@
|
||||
vuls
|
||||
.vscode
|
||||
*.txt
|
||||
*.json
|
||||
*.swp
|
||||
*.sqlite3*
|
||||
*.db
|
||||
tags
|
||||
@@ -10,6 +9,13 @@ coverage.out
|
||||
issues/
|
||||
vendor/
|
||||
log/
|
||||
results/
|
||||
*config.toml
|
||||
results
|
||||
!integration/data/results
|
||||
config.toml
|
||||
!setup/docker/*
|
||||
.DS_Store
|
||||
dist/
|
||||
.idea
|
||||
vuls.*
|
||||
vuls
|
||||
!cmd/vuls
|
||||
|
||||
47
.golangci.yml
Normal file
47
.golangci.yml
Normal file
@@ -0,0 +1,47 @@
|
||||
name: golang-ci
|
||||
|
||||
linters-settings:
|
||||
revive:
|
||||
# see https://github.com/mgechev/revive#available-rules for details.
|
||||
ignore-generated-header: true
|
||||
severity: warning
|
||||
confidence: 0.8
|
||||
rules:
|
||||
- name: blank-imports
|
||||
- name: context-as-argument
|
||||
- name: context-keys-type
|
||||
- name: dot-imports
|
||||
- name: error-return
|
||||
- name: error-strings
|
||||
- name: error-naming
|
||||
- name: exported
|
||||
- name: if-return
|
||||
- name: increment-decrement
|
||||
- name: var-naming
|
||||
- name: var-declaration
|
||||
- name: package-comments
|
||||
- name: range
|
||||
- name: receiver-naming
|
||||
- name: time-naming
|
||||
- name: unexported-return
|
||||
- name: indent-error-flow
|
||||
- name: errorf
|
||||
- name: empty-block
|
||||
- name: superfluous-else
|
||||
- name: unused-parameter
|
||||
- name: unreachable-code
|
||||
- name: redefines-builtin-id
|
||||
# errcheck:
|
||||
#exclude: /path/to/file.txt
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- goimports
|
||||
- revive
|
||||
- govet
|
||||
- misspell
|
||||
- errcheck
|
||||
- staticcheck
|
||||
- prealloc
|
||||
- ineffassign
|
||||
104
.goreleaser.yml
104
.goreleaser.yml
@@ -1,23 +1,113 @@
|
||||
project_name: vuls
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
release:
|
||||
github:
|
||||
owner: future-architect
|
||||
name: vuls
|
||||
builds:
|
||||
- goos:
|
||||
- id: vuls
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- amd64
|
||||
main: .
|
||||
ldflags: -s -w -X main.version={{.Version}} -X main.revision={{.Commit}}
|
||||
main: ./cmd/vuls/main.go
|
||||
flags:
|
||||
- -a
|
||||
ldflags:
|
||||
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
|
||||
binary: vuls
|
||||
archive:
|
||||
|
||||
- id: vuls-scanner
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
- arm
|
||||
- arm64
|
||||
main: ./cmd/scanner/main.go
|
||||
flags:
|
||||
- -a
|
||||
tags:
|
||||
- scanner
|
||||
ldflags:
|
||||
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
|
||||
binary: vuls-scanner
|
||||
|
||||
- id: trivy-to-vuls
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
- arm
|
||||
- arm64
|
||||
tags:
|
||||
- scanner
|
||||
main: ./contrib/trivy/cmd/main.go
|
||||
binary: trivy-to-vuls
|
||||
|
||||
- id: future-vuls
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
- arm
|
||||
- arm64
|
||||
flags:
|
||||
- -a
|
||||
tags:
|
||||
- scanner
|
||||
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
|
||||
- README*
|
||||
- CHANGELOG.md
|
||||
|
||||
- id: vuls-scanner
|
||||
name_template: '{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
|
||||
builds:
|
||||
- vuls-scanner
|
||||
format: tar.gz
|
||||
files:
|
||||
- LICENSE
|
||||
- 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
|
||||
- README*
|
||||
- CHANGELOG.md
|
||||
|
||||
- id: future-vuls
|
||||
name_template: '{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
|
||||
builds:
|
||||
- future-vuls
|
||||
format: tar.gz
|
||||
name_template: '{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{
|
||||
.Arm }}{{ end }}'
|
||||
files:
|
||||
- LICENSE
|
||||
- NOTICE
|
||||
- README*
|
||||
- CHANGELOG.md
|
||||
snapshot:
|
||||
|
||||
30
.revive.toml
Normal file
30
.revive.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
ignoreGeneratedHeader = false
|
||||
severity = "warning"
|
||||
confidence = 0.8
|
||||
errorCode = 0
|
||||
warningCode = 0
|
||||
|
||||
[rule.blank-imports]
|
||||
[rule.context-as-argument]
|
||||
[rule.context-keys-type]
|
||||
[rule.dot-imports]
|
||||
[rule.error-return]
|
||||
[rule.error-strings]
|
||||
[rule.error-naming]
|
||||
[rule.exported]
|
||||
[rule.if-return]
|
||||
[rule.increment-decrement]
|
||||
[rule.var-naming]
|
||||
[rule.var-declaration]
|
||||
[rule.package-comments]
|
||||
[rule.range]
|
||||
[rule.receiver-naming]
|
||||
[rule.time-naming]
|
||||
[rule.unexported-return]
|
||||
[rule.indent-error-flow]
|
||||
[rule.errorf]
|
||||
[rule.empty-block]
|
||||
[rule.superfluous-else]
|
||||
[rule.unused-parameter]
|
||||
[rule.unreachable-code]
|
||||
[rule.redefines-builtin-id]
|
||||
@@ -1,7 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- "1.11.x"
|
||||
|
||||
after_success:
|
||||
- test -n "$TRAVIS_TAG" && curl -sL https://git.io/goreleaser | bash
|
||||
@@ -10,10 +10,7 @@ ENV REPOSITORY github.com/future-architect/vuls
|
||||
COPY . $GOPATH/src/$REPOSITORY
|
||||
RUN cd $GOPATH/src/$REPOSITORY && make install
|
||||
|
||||
|
||||
FROM alpine:3.7
|
||||
|
||||
MAINTAINER hikachan sadayuki-matsuno
|
||||
FROM alpine:3.14
|
||||
|
||||
ENV LOGDIR /var/log/vuls
|
||||
ENV WORKDIR /vuls
|
||||
@@ -21,11 +18,13 @@ ENV WORKDIR /vuls
|
||||
RUN apk add --no-cache \
|
||||
openssh-client \
|
||||
ca-certificates \
|
||||
git \
|
||||
nmap \
|
||||
&& mkdir -p $WORKDIR $LOGDIR
|
||||
|
||||
COPY --from=builder /go/bin/vuls /usr/local/bin/
|
||||
|
||||
VOLUME [$WORKDIR, $LOGDIR]
|
||||
VOLUME ["$WORKDIR", "$LOGDIR"]
|
||||
WORKDIR $WORKDIR
|
||||
ENV PWD $WORKDIR
|
||||
|
||||
|
||||
214
GNUmakefile
214
GNUmakefile
@@ -1,11 +1,9 @@
|
||||
.PHONY: \
|
||||
dep \
|
||||
depup \
|
||||
build \
|
||||
install \
|
||||
all \
|
||||
vendor \
|
||||
lint \
|
||||
lint \
|
||||
vet \
|
||||
fmt \
|
||||
fmtcheck \
|
||||
@@ -21,31 +19,37 @@ 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
|
||||
CGO_UNABLED := CGO_ENABLED=0 go
|
||||
GO_OFF := GO111MODULE=off go
|
||||
|
||||
all: dep build
|
||||
|
||||
dep:
|
||||
go get -u github.com/golang/dep/...
|
||||
dep ensure -v
|
||||
all: b
|
||||
|
||||
depup:
|
||||
go get -u github.com/golang/dep/...
|
||||
dep ensure -update -v
|
||||
build: ./cmd/vuls/main.go pretest fmt
|
||||
$(GO) build -a -ldflags "$(LDFLAGS)" -o vuls ./cmd/vuls
|
||||
|
||||
build: main.go dep pretest
|
||||
go build -ldflags "$(LDFLAGS)" -o vuls $<
|
||||
b: ./cmd/vuls/main.go
|
||||
$(GO) build -a -ldflags "$(LDFLAGS)" -o vuls ./cmd/vuls
|
||||
|
||||
install: main.go dep pretest
|
||||
go install -ldflags "$(LDFLAGS)"
|
||||
install: ./cmd/vuls/main.go
|
||||
$(GO) install -ldflags "$(LDFLAGS)" ./cmd/vuls
|
||||
|
||||
build-scanner: ./cmd/scanner/main.go
|
||||
$(CGO_UNABLED) build -tags=scanner -a -ldflags "$(LDFLAGS)" -o vuls ./cmd/scanner
|
||||
|
||||
install-scanner: ./cmd/scanner/main.go
|
||||
$(CGO_UNABLED) install -tags=scanner -ldflags "$(LDFLAGS)" ./cmd/scanner
|
||||
|
||||
lint:
|
||||
@ go get -v golang.org/x/lint/golint
|
||||
golint $(PKGS)
|
||||
$(GO_OFF) get -u github.com/mgechev/revive
|
||||
revive -config ./.revive.toml -formatter plain $(PKGS)
|
||||
|
||||
vet:
|
||||
# @-go get -v golang.org/x/tools/cmd/vet
|
||||
go vet ./... || exit;
|
||||
echo $(PKGS) | xargs env $(GO) vet || exit;
|
||||
|
||||
golangci:
|
||||
golangci-lint run
|
||||
|
||||
fmt:
|
||||
gofmt -s -w $(SRCS)
|
||||
@@ -56,10 +60,10 @@ mlint:
|
||||
fmtcheck:
|
||||
$(foreach file,$(SRCS),gofmt -s -d $(file);)
|
||||
|
||||
pretest: lint vet fmtcheck
|
||||
pretest: lint vet fmtcheck golangci
|
||||
|
||||
test:
|
||||
echo $(PKGS) | xargs go test -cover -v || exit;
|
||||
$(GO) test -cover -v ./... || exit;
|
||||
|
||||
unused:
|
||||
$(foreach pkg,$(PKGS),unused $(pkg);)
|
||||
@@ -67,8 +71,176 @@ unused:
|
||||
cov:
|
||||
@ go get -v github.com/axw/gocov/gocov
|
||||
@ go get golang.org/x/tools/cmd/cover
|
||||
gocov test | gocov report
|
||||
gocov test -v ./... | 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
|
||||
|
||||
|
||||
# integration-test
|
||||
BASE_DIR := '${PWD}/integration/results'
|
||||
# $(shell mkdir -p ${BASE_DIR})
|
||||
NOW=$(shell date --iso-8601=seconds)
|
||||
NOW_JSON_DIR := '${BASE_DIR}/$(NOW)'
|
||||
ONE_SEC_AFTER=$(shell date -d '+1 second' --iso-8601=seconds)
|
||||
ONE_SEC_AFTER_JSON_DIR := '${BASE_DIR}/$(ONE_SEC_AFTER)'
|
||||
LIBS := 'gemfile' 'pipfile' 'poetry' 'composer' 'packagelock' 'yarn' 'cargo' 'gomod' 'nvd_exact' 'nvd_rough' 'nvd_vendor_product' 'nvd_match_no_jvn' 'jvn_vendor_product' 'jvn_vendor_product_nover'
|
||||
|
||||
diff:
|
||||
# git clone git@github.com:vulsio/vulsctl.git
|
||||
# cd vulsctl/docker
|
||||
# ./update-all.sh
|
||||
# cd /path/to/vuls
|
||||
# vim integration/int-config.toml
|
||||
# ln -s vuls vuls.new
|
||||
# ln -s oldvuls vuls.old
|
||||
# make int
|
||||
# (ex. test 10 times: for i in `seq 10`; do make int ARGS=-quiet ; done)
|
||||
ifneq ($(shell ls -U1 ${BASE_DIR} | wc -l), 0)
|
||||
mv ${BASE_DIR} /tmp/${NOW}
|
||||
endif
|
||||
mkdir -p ${NOW_JSON_DIR}
|
||||
sleep 1
|
||||
./vuls.old scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
|
||||
cp ${BASE_DIR}/current/*.json ${NOW_JSON_DIR}
|
||||
- cp integration/data/results/*.json ${NOW_JSON_DIR}
|
||||
./vuls.old report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-config.toml ${NOW}
|
||||
|
||||
mkdir -p ${ONE_SEC_AFTER_JSON_DIR}
|
||||
sleep 1
|
||||
./vuls.new scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
|
||||
cp ${BASE_DIR}/current/*.json ${ONE_SEC_AFTER_JSON_DIR}
|
||||
- cp integration/data/results/*.json ${ONE_SEC_AFTER_JSON_DIR}
|
||||
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-config.toml ${ONE_SEC_AFTER}
|
||||
|
||||
$(call sed-d)
|
||||
- diff -c ${NOW_JSON_DIR} ${ONE_SEC_AFTER_JSON_DIR}
|
||||
echo "old: ${NOW_JSON_DIR} , new: ${ONE_SEC_AFTER_JSON_DIR}"
|
||||
$(call count-cve)
|
||||
|
||||
diff-redis:
|
||||
# docker network create redis-nw
|
||||
# docker run --name redis -d --network redis-nw -p 127.0.0.1:6379:6379 redis
|
||||
# git clone git@github.com:vulsio/vulsctl.git
|
||||
# cd vulsctl/docker
|
||||
# ./update-all-redis.sh
|
||||
# (or export DOCKER_NETWORK=redis-nw; cd /home/ubuntu/vulsctl/docker; ./update-all.sh --dbtype redis --dbpath "redis://redis/0")
|
||||
# vim integration/int-redis-config.toml
|
||||
# ln -s vuls vuls.new
|
||||
# ln -s oldvuls vuls.old
|
||||
# make int-redis
|
||||
ifneq ($(shell ls -U1 ${BASE_DIR} | wc -l), 0)
|
||||
mv ${BASE_DIR} /tmp/${NOW}
|
||||
endif
|
||||
mkdir -p ${NOW_JSON_DIR}
|
||||
sleep 1
|
||||
./vuls.old scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
|
||||
cp -f ${BASE_DIR}/current/*.json ${NOW_JSON_DIR}
|
||||
- cp integration/data/results/*.json ${NOW_JSON_DIR}
|
||||
./vuls.old report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-redis-config.toml ${NOW}
|
||||
|
||||
mkdir -p ${ONE_SEC_AFTER_JSON_DIR}
|
||||
sleep 1
|
||||
./vuls.new scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
|
||||
cp -f ${BASE_DIR}/current/*.json ${ONE_SEC_AFTER_JSON_DIR}
|
||||
- cp integration/data/results/*.json ${ONE_SEC_AFTER_JSON_DIR}
|
||||
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-redis-config.toml ${ONE_SEC_AFTER}
|
||||
|
||||
$(call sed-d)
|
||||
- diff -c ${NOW_JSON_DIR} ${ONE_SEC_AFTER_JSON_DIR}
|
||||
echo "old: ${NOW_JSON_DIR} , new: ${ONE_SEC_AFTER_JSON_DIR}"
|
||||
$(call count-cve)
|
||||
|
||||
diff-rdb-redis:
|
||||
ifneq ($(shell ls -U1 ${BASE_DIR} | wc -l), 0)
|
||||
mv ${BASE_DIR} /tmp/${NOW}
|
||||
endif
|
||||
mkdir -p ${NOW_JSON_DIR}
|
||||
sleep 1
|
||||
# new vs new
|
||||
./vuls.new scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
|
||||
cp -f ${BASE_DIR}/current/*.json ${NOW_JSON_DIR}
|
||||
cp integration/data/results/*.json ${NOW_JSON_DIR}
|
||||
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-config.toml ${NOW}
|
||||
|
||||
mkdir -p ${ONE_SEC_AFTER_JSON_DIR}
|
||||
sleep 1
|
||||
./vuls.new scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
|
||||
cp -f ${BASE_DIR}/current/*.json ${ONE_SEC_AFTER_JSON_DIR}
|
||||
cp integration/data/results/*.json ${ONE_SEC_AFTER_JSON_DIR}
|
||||
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-redis-config.toml ${ONE_SEC_AFTER}
|
||||
|
||||
$(call sed-d)
|
||||
- diff -c ${NOW_JSON_DIR} ${ONE_SEC_AFTER_JSON_DIR}
|
||||
echo "old: ${NOW_JSON_DIR} , new: ${ONE_SEC_AFTER_JSON_DIR}"
|
||||
$(call count-cve)
|
||||
|
||||
head= $(shell git rev-parse HEAD)
|
||||
prev= $(shell git rev-parse HEAD^)
|
||||
branch=$(shell git rev-parse --abbrev-ref HEAD)
|
||||
build-integration:
|
||||
git stash
|
||||
|
||||
# buld HEAD
|
||||
git checkout ${head}
|
||||
make build
|
||||
mv -f ./vuls ./vuls.${head}
|
||||
|
||||
# HEAD^
|
||||
git checkout ${prev}
|
||||
make build
|
||||
mv -f ./vuls ./vuls.${prev}
|
||||
|
||||
# master
|
||||
git checkout master
|
||||
make build
|
||||
mv -f ./vuls ./vuls.master
|
||||
|
||||
# working tree
|
||||
git checkout ${branch}
|
||||
git stash apply stash@\{0\}
|
||||
make build
|
||||
|
||||
# for integration testing, vuls.new and vuls.old needed.
|
||||
# ex)
|
||||
# $ ln -s ./vuls ./vuls.new
|
||||
# $ ln -s ./vuls.${head} ./vuls.old
|
||||
# or
|
||||
# $ ln -s ./vuls.${prev} ./vuls.old
|
||||
# then
|
||||
# $ make diff
|
||||
# $ make diff-redis
|
||||
# $ make diff-rdb-redis
|
||||
|
||||
|
||||
define sed-d
|
||||
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/scannedAt/d' {} \;
|
||||
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/scannedAt/d' {} \;
|
||||
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/reportedAt/d' {} \;
|
||||
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/reportedAt/d' {} \;
|
||||
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/"Type":/d' {} \;
|
||||
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/"Type":/d' {} \;
|
||||
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/"SQLite3Path":/d' {} \;
|
||||
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/"SQLite3Path":/d' {} \;
|
||||
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/reportedRevision/d' {} \;
|
||||
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/reportedRevision/d' {} \;
|
||||
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/scannedRevision/d' {} \;
|
||||
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/scannedRevision/d' {} \;
|
||||
endef
|
||||
|
||||
define count-cve
|
||||
for jsonfile in ${NOW_JSON_DIR}/*.json ; do \
|
||||
echo $$jsonfile; cat $$jsonfile | jq ".scannedCves | length" ; \
|
||||
done
|
||||
for jsonfile in ${ONE_SEC_AFTER_JSON_DIR}/*.json ; do \
|
||||
echo $$jsonfile; cat $$jsonfile | jq ".scannedCves | length" ; \
|
||||
done
|
||||
endef
|
||||
|
||||
991
Gopkg.lock
generated
991
Gopkg.lock
generated
@@ -1,991 +0,0 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b92928b73320648b38c93cacb9082c0fe3f8ac3383ad9bd537eef62c380e0e7a"
|
||||
name = "contrib.go.opencensus.io/exporter/ocagent"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "00af367e65149ff1f2f4b93bbfbb84fd9297170d"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a90dbfc07d4cf47b5f113a2d52227e0b098592b22c0bd7afd731f6cb8bd9d55c"
|
||||
name = "github.com/Azure/azure-sdk-for-go"
|
||||
packages = [
|
||||
"storage",
|
||||
"version",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "1951233eb944a49aa5f7278cba8e3e32a8c958af"
|
||||
version = "v24.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e6c692a2dd5f978216331f2ab41b45dfdf01d5b2a74c596a9f69bcef77b7d67b"
|
||||
name = "github.com/Azure/go-autorest"
|
||||
packages = [
|
||||
"autorest",
|
||||
"autorest/adal",
|
||||
"autorest/azure",
|
||||
"autorest/date",
|
||||
"logger",
|
||||
"tracing",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "be17756531f50014397912b7aa557ec335e39b98"
|
||||
version = "v11.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9f3b30d9f8e0d7040f729b82dcbc8f0dead820a133b3147ce355fc451f32d761"
|
||||
name = "github.com/BurntSushi/toml"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005"
|
||||
version = "v0.3.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:bb6c15391e666c4f44bdc604772301b93102233ed687be6df6d1c2abbde4f15c"
|
||||
name = "github.com/RackSec/srslog"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "a4725f04ec91af1a91b380da679d6e0c2f061e59"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:320e7ead93de9fd2b0e59b50fd92a4d50c1f8ab455d96bc2eb083267453a9709"
|
||||
name = "github.com/asaskevich/govalidator"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "ccb8e960c48f04d6935e72476ae4a51028f9e22f"
|
||||
version = "v9"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5652bf3ce03ccaeb93cd5e11fcaab25467f78275fd9c4b4d1ffe88aae6faed12"
|
||||
name = "github.com/aws/aws-sdk-go"
|
||||
packages = [
|
||||
"aws",
|
||||
"aws/awserr",
|
||||
"aws/awsutil",
|
||||
"aws/client",
|
||||
"aws/client/metadata",
|
||||
"aws/corehandlers",
|
||||
"aws/credentials",
|
||||
"aws/credentials/ec2rolecreds",
|
||||
"aws/credentials/endpointcreds",
|
||||
"aws/credentials/processcreds",
|
||||
"aws/credentials/stscreds",
|
||||
"aws/csm",
|
||||
"aws/defaults",
|
||||
"aws/ec2metadata",
|
||||
"aws/endpoints",
|
||||
"aws/request",
|
||||
"aws/session",
|
||||
"aws/signer/v4",
|
||||
"internal/ini",
|
||||
"internal/s3err",
|
||||
"internal/sdkio",
|
||||
"internal/sdkrand",
|
||||
"internal/sdkuri",
|
||||
"internal/shareddefaults",
|
||||
"private/protocol",
|
||||
"private/protocol/eventstream",
|
||||
"private/protocol/eventstream/eventstreamapi",
|
||||
"private/protocol/query",
|
||||
"private/protocol/query/queryutil",
|
||||
"private/protocol/rest",
|
||||
"private/protocol/restxml",
|
||||
"private/protocol/xml/xmlutil",
|
||||
"service/s3",
|
||||
"service/sts",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "aabf189db35ba7eb5a35afe6d681fc0f70954fca"
|
||||
version = "v1.16.18"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0f98f59e9a2f4070d66f0c9c39561f68fcd1dc837b22a852d28d0003aebd1b1e"
|
||||
name = "github.com/boltdb/bolt"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "2f1ce7a837dcb8da3ec595b1dac9d0632f0f99e8"
|
||||
version = "v1.3.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:166438587ed45ac211dab8a3ecebf4fa0c186d0db63430fb9127bbc2e5fcdc67"
|
||||
name = "github.com/cenkalti/backoff"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "1e4cf3da559842a91afcb6ea6141451e6c30c618"
|
||||
version = "v2.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:65b0d980b428a6ad4425f2df4cd5410edd81f044cf527bd1c345368444649e58"
|
||||
name = "github.com/census-instrumentation/opencensus-proto"
|
||||
packages = [
|
||||
"gen-go/agent/common/v1",
|
||||
"gen-go/agent/trace/v1",
|
||||
"gen-go/resource/v1",
|
||||
"gen-go/trace/v1",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "7f2434bc10da710debe5c4315ed6d4df454b4024"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e04c00d619875ce5fa67180891984a9b1fadcc031af36bcd7a3509cbdad1df15"
|
||||
name = "github.com/cheggaaa/pb"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c112833d014c77e8bde723fd0158e3156951639f"
|
||||
version = "v2.0.6"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||
version = "v3.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:865079840386857c809b72ce300be7580cb50d3d3129ce11bf9aa6ca2bc1934a"
|
||||
name = "github.com/fatih/color"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4"
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd"
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||
version = "v1.4.7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ad53d1f710522a38d1f0e5e0a55a194b1c6b2cd8e84313568e43523271f0cf62"
|
||||
name = "github.com/go-redis/redis"
|
||||
packages = [
|
||||
".",
|
||||
"internal",
|
||||
"internal/consistenthash",
|
||||
"internal/hashtag",
|
||||
"internal/pool",
|
||||
"internal/proto",
|
||||
"internal/util",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "22be8a3eaf992c828cecb69dc07348313bf08d2e"
|
||||
version = "v6.15.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ec6f9bf5e274c833c911923c9193867f3f18788c461f76f05f62bb1510e0ae65"
|
||||
name = "github.com/go-sql-driver/mysql"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "72cd26f257d44c1114970e19afddcd812016007e"
|
||||
version = "v1.4.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:586ea76dbd0374d6fb649a91d70d652b7fe0ccffb8910a77468e7702e7901f3d"
|
||||
name = "github.com/go-stack/stack"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a"
|
||||
version = "v1.8.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8f0705fa33e8957018611cc81c65cb373b626c092d39931bb86882489fc4c3f4"
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = [
|
||||
"proto",
|
||||
"ptypes",
|
||||
"ptypes/any",
|
||||
"ptypes/duration",
|
||||
"ptypes/timestamp",
|
||||
"ptypes/wrappers",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:df265b7f54410945dad5cf5979d91461b9fa7ff9b397ab58d2d577002a8a0e24"
|
||||
name = "github.com/google/subcommands"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "46f0354f63152e8801bb460d26f5b6c4c878efbb"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7b5c6e2eeaa9ae5907c391a91c132abfd5c9e8a784a341b5625e750c67e6825d"
|
||||
name = "github.com/gorilla/websocket"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:4e08dc2383a46b3107f0b34ca338c4459e8fc8ee90e46a60e728aa8a2b21d558"
|
||||
name = "github.com/gosuri/uitable"
|
||||
packages = [
|
||||
".",
|
||||
"util/strutil",
|
||||
"util/wordwrap",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "36ee7e946282a3fb1cfecd476ddc9b35d8847e42"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:8dbe76014be3c83806abc61befcb5e1789d2d872bc8f98a8fb955405550c63be"
|
||||
name = "github.com/grokify/html-strip-tags-go"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "e9e44961e26f513866063f54bf85070db95600f7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:950caca7dfcf796419232ba996c9c3539d09f26af27ba848c4508e604c13efbb"
|
||||
name = "github.com/hashicorp/go-version"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "d40cf49b3a77bba84a7afdbd7f1dc295d114efb1"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10"
|
||||
name = "github.com/hashicorp/hcl"
|
||||
packages = [
|
||||
".",
|
||||
"hcl/ast",
|
||||
"hcl/parser",
|
||||
"hcl/printer",
|
||||
"hcl/scanner",
|
||||
"hcl/strconv",
|
||||
"hcl/token",
|
||||
"json/parser",
|
||||
"json/scanner",
|
||||
"json/token",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:0f8b63af5601a93b6b6a63a420c857819e98a252369262d8faf66f3566ba294e"
|
||||
name = "github.com/hashicorp/uuid"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "ebb0a03e909c9c642a36d2527729104324c44fdb"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:0778dc7fce1b4669a8bfa7ae506ec1f595b6ab0f8989c1c0d22a8ca1144e9972"
|
||||
name = "github.com/howeyc/gopass"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "bf9dde6d0d2c004a008c27aaee91170c786f6db8"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e96640e5b9ce93e2d7ee18f48048483080fd23e72e3c38bc17e9c8b77062031a"
|
||||
name = "github.com/inconshreveable/log15"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "67afb5ed74ec82fd7ac8f49d27c509ac6f991970"
|
||||
version = "v2.14"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ff312c4d510c67954a6fc6a11c9ff72a2b2169584776b7419c7b8c729e2b13ac"
|
||||
name = "github.com/jinzhu/gorm"
|
||||
packages = [
|
||||
".",
|
||||
"dialects/mysql",
|
||||
"dialects/postgres",
|
||||
"dialects/sqlite",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "472c70caa40267cb89fd8facb07fe6454b578626"
|
||||
version = "v1.9.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:fd97437fbb6b7dce04132cf06775bd258cce305c44add58eb55ca86c6c325160"
|
||||
name = "github.com/jinzhu/inflection"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "04140366298a54a039076d798123ffa108fff46c"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:bb81097a5b62634f3e9fec1014657855610c82d19b9a40c17612e32651e35dca"
|
||||
name = "github.com/jmespath/go-jmespath"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c2b33e84"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:114ecad51af93a73ae6781fd0d0bc28e52b433c852b84ab4b4c109c15e6c6b6d"
|
||||
name = "github.com/jroimartin/gocui"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c055c87ae801372cd74a0839b972db4f7697ae5f"
|
||||
version = "v0.4.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:16dd6b893b78a50564cdde1d9f7ea67224dece11bb0886bd882f1dc3dc1d440d"
|
||||
name = "github.com/k0kubun/pp"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "027a6d1765d673d337e687394dbe780dd64e2a1e"
|
||||
version = "v2.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:bdf08c9b41c029c60ba5dc99443a3ce74eedad842cf2adf9c255513f432422e2"
|
||||
name = "github.com/knqyf263/go-cpe"
|
||||
packages = [
|
||||
"common",
|
||||
"matching",
|
||||
"naming",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "659663f6eca2ff32258e282557e7808115ea498a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:a9955a589c7f6f28bd5a5f69da3f1e2cc857c23c7605c5fa7b605f065ba8f3fe"
|
||||
name = "github.com/knqyf263/go-deb-version"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "9865fe14d09b1c729188ac810466dde90f897ee3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5734c5362ef66c39ddf1b4a11dfe75fa3c1adb70e78059543c83c0c6e89f2bc0"
|
||||
name = "github.com/knqyf263/go-rpm-version"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "74609b86c936dff800c69ec89fcf4bc52d5f13a4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:acca5c567e76e94e81f8d65893e2a9cd12d914dd688731f461a5ebdb180d4938"
|
||||
name = "github.com/knqyf263/gost"
|
||||
packages = [
|
||||
"config",
|
||||
"db",
|
||||
"models",
|
||||
"util",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "5afeda5e8e1f8f3561738d3d6fa6549c88feb31e"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8"
|
||||
name = "github.com/konsorten/go-windows-terminal-sequences"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:fa59fec07121e6190139b5134524c4fc7a6abe5143a775a0e17313b6997e17a7"
|
||||
name = "github.com/kotakanbe/go-cve-dictionary"
|
||||
packages = [
|
||||
"config",
|
||||
"db",
|
||||
"log",
|
||||
"models",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "b083bedef97055c27d1f039428ab183eca7c6450"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:54d3c90db1164399906830313a6fce7770917d7e4a12da8f2d8693d18ff5ef27"
|
||||
name = "github.com/kotakanbe/go-pingscanner"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "641dc2cc2d3cbf295dad356667b74c69bcbd6f70"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8fd95e6bab4d09a0f610bd5c02ef6ec7d0d91da5a72b7cfcbfd67254bcb72b75"
|
||||
name = "github.com/kotakanbe/goval-dictionary"
|
||||
packages = [
|
||||
"config",
|
||||
"db",
|
||||
"db/rdb",
|
||||
"models",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "5070051ecafdf15cbe2490e71ec038de7d25b71e"
|
||||
version = "v0.1.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:0daead102d7ca3af110dfb832e8c14393f197d94e5ffe3f0639f10ea2cc55530"
|
||||
name = "github.com/kotakanbe/logrus-prefixed-formatter"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "928f7356cb964637e2489a6ef37eee55181676c5"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:01eb0269028d3c2e21b5b6cd9b1ba81bc4170ab293fcffa84e3aa3a6138a92e8"
|
||||
name = "github.com/labstack/gommon"
|
||||
packages = [
|
||||
"color",
|
||||
"log",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "7fd9f68ece0bcb1a905fac8f1549f0083f71c51b"
|
||||
version = "v0.2.8"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b18ffc558326ebaed3b4a175617f1e12ed4e3f53d6ebfe5ba372a3de16d22278"
|
||||
name = "github.com/lib/pq"
|
||||
packages = [
|
||||
".",
|
||||
"hstore",
|
||||
"oid",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "4ded0e9383f75c197b3a2aaa6d590ac52df6fd79"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c568d7727aa262c32bdf8a3f7db83614f7af0ed661474b24588de635c20024c7"
|
||||
name = "github.com/magiconair/properties"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c2353362d570a7bfa228149c62842019201cfb71"
|
||||
version = "v1.8.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4e878df5f4e9fd625bf9c9aac77ef7cbfa4a74c01265505527c23470c0e40300"
|
||||
name = "github.com/marstr/guid"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "8bd9a64bf37eb297b492a4101fb28e80ac0b290f"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67"
|
||||
name = "github.com/mattn/go-colorable"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
||||
version = "v0.0.9"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0981502f9816113c9c8c4ac301583841855c8cf4da8c72f696b3ebedf6d0e4e5"
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c"
|
||||
version = "v0.0.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0356f3312c9bd1cbeda81505b7fd437501d8e778ab66998ef69f00d7f9b3a0d7"
|
||||
name = "github.com/mattn/go-runewidth"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "3ee7d812e62a0804a7d0a324e0249ca2db3476d3"
|
||||
version = "v0.0.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4a49346ca45376a2bba679ca0e83bec949d780d4e927931317904bad482943ec"
|
||||
name = "github.com/mattn/go-sqlite3"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c7c4067b79cc51e6dfdcef5c702e74b1e0fa7c75"
|
||||
version = "v1.10.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2b32af4d2a529083275afc192d1067d8126b578c7a9613b26600e4df9c735155"
|
||||
name = "github.com/mgutz/ansi"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "9520e82c474b0a04dd04f8a40959027271bab992"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:78bbb1ba5b7c3f2ed0ea1eab57bdd3859aec7e177811563edc41198a760b06af"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:53bc4cd4914cd7cd52139990d5170d6dc99067ae31c56530621b18b35fc30318"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "3536a929edddb9a5b34bd6861dc4a9647cb459fe"
|
||||
version = "v1.1.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7aefb397a53fc437c90f0fdb3e1419c751c5a3a165ced52325d5d797edf1aca6"
|
||||
name = "github.com/moul/http2curl"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "9ac6cf4d929b2fa8fd2d2e6dec5bb0feb4f4911d"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:a440c18972e9499a1e8de68915e5a9119008d86efc2a9c6c6edddc323ce6f3ed"
|
||||
name = "github.com/mozqnet/go-exploitdb"
|
||||
packages = [
|
||||
"db",
|
||||
"models",
|
||||
"util",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "652ae1f6aa234a4e22c8a6c9566ef4018a1d28c8"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:95d38d218bf2290987c6b0e885a9f0f2d3d3239235acaddca01c3fe36e5e5566"
|
||||
name = "github.com/nlopes/slack"
|
||||
packages = [
|
||||
".",
|
||||
"slackutilsx",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "b9033a72a20bf84563485e86a2adbea4bf265804"
|
||||
version = "v0.4.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:f3fc7efada7606d5abc88372e1f838ed897fa522077957070fbc2207a50d6faa"
|
||||
name = "github.com/nsf/termbox-go"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "0938b5187e61bb8c4dcac2b0a9cf4047d83784fc"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:abcdbf03ca6ca13d3697e2186edc1f33863bbdac2b3a44dfa39015e8903f7409"
|
||||
name = "github.com/olekukonko/tablewriter"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "e6d60cf7ba1f42d86d54cdf5508611c4aafb3970"
|
||||
version = "v0.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d776f3e95774a8719f2e57fabbbb33103035fe072dcf6f1864f33abd17b753e5"
|
||||
name = "github.com/parnurzeal/gorequest"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "a578a48e8d6ca8b01a3b18314c43c6716bb5f5a3"
|
||||
version = "v0.2.15"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e"
|
||||
name = "github.com/pelletier/go-toml"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b"
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
|
||||
version = "v0.8.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1a23fdd843129ef761ffe7651bc5fe7c5b09fbe933e92783ab06cc11c37b7b37"
|
||||
name = "github.com/rifflock/lfshook"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "b9218ef580f59a2e72dad1aa33d660150445d05a"
|
||||
version = "v2.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:274f67cb6fed9588ea2521ecdac05a6d62a8c51c074c1fccc6a49a40ba80e925"
|
||||
name = "github.com/satori/go.uuid"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:9c3c856c4bd09733de5727aeb85fc484b8b87a6eb9e6a632c47e3f17142757ee"
|
||||
name = "github.com/sirupsen/logrus"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "78fb3852d92683dc28da6cc3d5f965100677c27d"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d707dbc1330c0ed177d4642d6ae102d5e2c847ebd0eb84562d0dc4f024531cfc"
|
||||
name = "github.com/spf13/afero"
|
||||
packages = [
|
||||
".",
|
||||
"mem",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "a5d6946387efe7d64d09dcba68cdd523dc1273a3"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:08d65904057412fc0270fc4812a1c90c594186819243160dc779a402d4b6d0bc"
|
||||
name = "github.com/spf13/cast"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "8c9545af88b134710ab1cd196795e7f2388358d7"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:68ea4e23713989dc20b1bded5d9da2c5f9be14ff9885beef481848edd18c26cb"
|
||||
name = "github.com/spf13/jwalterweatherman"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "4a4406e478ca629068e7768fc33f3f044173c0a6"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
|
||||
version = "v1.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:de37e343c64582d7026bf8ab6ac5b22a72eac54f3a57020db31524affed9f423"
|
||||
name = "github.com/spf13/viper"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "6d33b5a963d922d182c91e8a1c88d81fd150cfd4"
|
||||
version = "v1.3.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c468422f334a6b46a19448ad59aaffdfc0a36b08fdcc1c749a0b29b6453d7e59"
|
||||
name = "github.com/valyala/bytebufferpool"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "e746df99fe4a3986f4d4f79e13c1e0117ce9c2f7"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:268b8bce0064e8c057d7b913605459f9a26dcab864c0886a56d196540fbf003f"
|
||||
name = "github.com/valyala/fasttemplate"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "dcecefd839c4193db0d35b88ec65b4c12d360ab0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:0792df7c7ff49b81c7a8c5a2a47aee897c5bab31fb348c8e2f80a560d675f941"
|
||||
name = "github.com/ymomoi/goval-parser"
|
||||
packages = ["oval"]
|
||||
pruneopts = "UT"
|
||||
revision = "0a0be1dd9d0855b50be0be5a10ad3085382b6d59"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2ae8314c44cd413cfdb5b1df082b350116dd8d2fff973e62c01b285b7affd89e"
|
||||
name = "go.opencensus.io"
|
||||
packages = [
|
||||
".",
|
||||
"exemplar",
|
||||
"internal",
|
||||
"internal/tagencoding",
|
||||
"plugin/ochttp",
|
||||
"plugin/ochttp/propagation/b3",
|
||||
"plugin/ochttp/propagation/tracecontext",
|
||||
"stats",
|
||||
"stats/internal",
|
||||
"stats/view",
|
||||
"tag",
|
||||
"trace",
|
||||
"trace/internal",
|
||||
"trace/propagation",
|
||||
"trace/tracestate",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "b7bf3cdb64150a8c8c53b769fdeb2ba581bd4d4b"
|
||||
version = "v0.18.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:30e9f5bea4df0d1a573ed89a85cc680ab05dfc078f6a21e627db236f29650a11"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"curve25519",
|
||||
"ed25519",
|
||||
"ed25519/internal/edwards25519",
|
||||
"internal/chacha20",
|
||||
"internal/subtle",
|
||||
"poly1305",
|
||||
"ssh",
|
||||
"ssh/agent",
|
||||
"ssh/terminal",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "ff983b9c42bc9fbf91556e191cc8efb585c16908"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:25c965216c188afcd5f430f65acc28d4f193c5a88e7c6c54ae876b1898f86368"
|
||||
name = "golang.org/x/net"
|
||||
packages = [
|
||||
"context",
|
||||
"context/ctxhttp",
|
||||
"http/httpguts",
|
||||
"http2",
|
||||
"http2/hpack",
|
||||
"idna",
|
||||
"internal/timeseries",
|
||||
"publicsuffix",
|
||||
"trace",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "915654e7eabcea33ae277abbecf52f0d8b7a9fdc"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:e007b54f54cbd4214aa6d97a67d57bc2539991adb4e22ea92c482bbece8de469"
|
||||
name = "golang.org/x/oauth2"
|
||||
packages = [
|
||||
".",
|
||||
"internal",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "99b60b757ec124ebb7d6b7e97f153b19c10ce163"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:75515eedc0dc2cb0b40372008b616fa2841d831c63eedd403285ff286c593295"
|
||||
name = "golang.org/x/sync"
|
||||
packages = ["semaphore"]
|
||||
pruneopts = "UT"
|
||||
revision = "37e7f081c4d4c64e13b10787722085407fe5d15f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5ee4df7ab18e945607ac822de8d10b180baea263b5e8676a1041727543b9c1e4"
|
||||
name = "golang.org/x/sys"
|
||||
packages = [
|
||||
"unix",
|
||||
"windows",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "48ac38b7c8cbedd50b1613c0fccacfc7d88dfcdf"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"collate",
|
||||
"collate/build",
|
||||
"internal/colltab",
|
||||
"internal/gen",
|
||||
"internal/tag",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"language",
|
||||
"secure/bidirule",
|
||||
"transform",
|
||||
"unicode/bidi",
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5f003878aabe31d7f6b842d4de32b41c46c214bb629bb485387dbcce1edf5643"
|
||||
name = "google.golang.org/api"
|
||||
packages = ["support/bundler"]
|
||||
pruneopts = "UT"
|
||||
revision = "19e022d8cf43ce81f046bae8cc18c5397cc7732f"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9e29a0ec029d012437d88da3ccccf18adcdce069cab08d462056c2c6bb006505"
|
||||
name = "google.golang.org/appengine"
|
||||
packages = [
|
||||
"cloudsql",
|
||||
"internal",
|
||||
"internal/base",
|
||||
"internal/datastore",
|
||||
"internal/log",
|
||||
"internal/remote_api",
|
||||
"internal/urlfetch",
|
||||
"urlfetch",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:077c1c599507b3b3e9156d17d36e1e61928ee9b53a5b420f10f28ebd4a0b275c"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
pruneopts = "UT"
|
||||
revision = "db91494dd46c1fdcbbde05e5ff5eb56df8f7d79a"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9edd250a3c46675d0679d87540b30c9ed253b19bd1fd1af08f4f5fb3c79fc487"
|
||||
name = "google.golang.org/grpc"
|
||||
packages = [
|
||||
".",
|
||||
"balancer",
|
||||
"balancer/base",
|
||||
"balancer/roundrobin",
|
||||
"binarylog/grpc_binarylog_v1",
|
||||
"codes",
|
||||
"connectivity",
|
||||
"credentials",
|
||||
"credentials/internal",
|
||||
"encoding",
|
||||
"encoding/proto",
|
||||
"grpclog",
|
||||
"internal",
|
||||
"internal/backoff",
|
||||
"internal/binarylog",
|
||||
"internal/channelz",
|
||||
"internal/envconfig",
|
||||
"internal/grpcrand",
|
||||
"internal/grpcsync",
|
||||
"internal/syscall",
|
||||
"internal/transport",
|
||||
"keepalive",
|
||||
"metadata",
|
||||
"naming",
|
||||
"peer",
|
||||
"resolver",
|
||||
"resolver/dns",
|
||||
"resolver/passthrough",
|
||||
"stats",
|
||||
"status",
|
||||
"tap",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "df014850f6dee74ba2fc94874043a9f3f75fbfd8"
|
||||
version = "v1.17.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e626376fab8608a972d47e91b3c1bbbddaecaf1d42b82be6dcc52d10a7557893"
|
||||
name = "gopkg.in/VividCortex/ewma.v1"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "b24eb346a94c3ba12c1da1e564dbac1b498a77ce"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:94cad6e2359d57da6652e689189c5b6ef19f99db6304d2c41de54f6632e15143"
|
||||
name = "gopkg.in/cheggaaa/pb.v1"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "1cc5bbe20449079337944d56292c7383510c534c"
|
||||
version = "v1.0.27"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:256938e7d43c73bd5e7bb97dd281d1ebe294b2928403ee1fbec96249915d1150"
|
||||
name = "gopkg.in/cheggaaa/pb.v2"
|
||||
packages = ["termutil"]
|
||||
pruneopts = "UT"
|
||||
revision = "c112833d014c77e8bde723fd0158e3156951639f"
|
||||
version = "v2.0.6"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:865079840386857c809b72ce300be7580cb50d3d3129ce11bf9aa6ca2bc1934a"
|
||||
name = "gopkg.in/fatih/color.v1"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4"
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67"
|
||||
name = "gopkg.in/mattn/go-colorable.v0"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
||||
version = "v0.0.9"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0981502f9816113c9c8c4ac301583841855c8cf4da8c72f696b3ebedf6d0e4e5"
|
||||
name = "gopkg.in/mattn/go-isatty.v0"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c"
|
||||
version = "v0.0.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0356f3312c9bd1cbeda81505b7fd437501d8e778ab66998ef69f00d7f9b3a0d7"
|
||||
name = "gopkg.in/mattn/go-runewidth.v0"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "3ee7d812e62a0804a7d0a324e0249ca2db3476d3"
|
||||
version = "v0.0.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
|
||||
version = "v2.2.2"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/Azure/azure-sdk-for-go/storage",
|
||||
"github.com/BurntSushi/toml",
|
||||
"github.com/RackSec/srslog",
|
||||
"github.com/asaskevich/govalidator",
|
||||
"github.com/aws/aws-sdk-go/aws",
|
||||
"github.com/aws/aws-sdk-go/aws/credentials",
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds",
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata",
|
||||
"github.com/aws/aws-sdk-go/aws/session",
|
||||
"github.com/aws/aws-sdk-go/service/s3",
|
||||
"github.com/aws/aws-sdk-go/service/sts",
|
||||
"github.com/boltdb/bolt",
|
||||
"github.com/cenkalti/backoff",
|
||||
"github.com/google/subcommands",
|
||||
"github.com/gosuri/uitable",
|
||||
"github.com/hashicorp/uuid",
|
||||
"github.com/howeyc/gopass",
|
||||
"github.com/jroimartin/gocui",
|
||||
"github.com/k0kubun/pp",
|
||||
"github.com/knqyf263/go-cpe/naming",
|
||||
"github.com/knqyf263/go-deb-version",
|
||||
"github.com/knqyf263/go-rpm-version",
|
||||
"github.com/knqyf263/gost/db",
|
||||
"github.com/knqyf263/gost/models",
|
||||
"github.com/kotakanbe/go-cve-dictionary/db",
|
||||
"github.com/kotakanbe/go-cve-dictionary/log",
|
||||
"github.com/kotakanbe/go-cve-dictionary/models",
|
||||
"github.com/kotakanbe/go-pingscanner",
|
||||
"github.com/kotakanbe/goval-dictionary/db",
|
||||
"github.com/kotakanbe/goval-dictionary/models",
|
||||
"github.com/kotakanbe/logrus-prefixed-formatter",
|
||||
"github.com/mitchellh/go-homedir",
|
||||
"github.com/mozqnet/go-exploitdb/db",
|
||||
"github.com/mozqnet/go-exploitdb/models",
|
||||
"github.com/nlopes/slack",
|
||||
"github.com/olekukonko/tablewriter",
|
||||
"github.com/parnurzeal/gorequest",
|
||||
"github.com/pkg/errors",
|
||||
"github.com/rifflock/lfshook",
|
||||
"github.com/sirupsen/logrus",
|
||||
"golang.org/x/crypto/ssh",
|
||||
"golang.org/x/crypto/ssh/agent",
|
||||
"golang.org/x/oauth2",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
41
Gopkg.toml
41
Gopkg.toml
@@ -1,41 +0,0 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/knqyf263/gost"
|
||||
branch = "master"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/kotakanbe/go-cve-dictionary"
|
||||
branch = "master"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mozqnet/go-exploitdb"
|
||||
branch = "master"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
153
LICENSE
153
LICENSE
@@ -1,23 +1,21 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
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 General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
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,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
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. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
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
|
||||
@@ -26,44 +24,34 @@ 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.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
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.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
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.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
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.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
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.
|
||||
@@ -72,7 +60,7 @@ modification follow.
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
"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.
|
||||
@@ -549,35 +537,45 @@ 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. Use with the GNU Affero General Public License.
|
||||
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 Affero General Public License into a single
|
||||
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 special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
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 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
|
||||
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 General
|
||||
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 General Public License, you may choose any version ever published
|
||||
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 General Public License can be used, that proxy's
|
||||
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.
|
||||
|
||||
@@ -631,44 +629,33 @@ 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.
|
||||
|
||||
Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
<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 General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
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 General Public License for more details.
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
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 the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
Vuls Copyright (C) 2016 Future Corporation , Japan.
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
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 GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
146
README.md
146
README.md
@@ -9,7 +9,7 @@
|
||||
|
||||

|
||||
|
||||
Vulnerability scanner for Linux/FreeBSD, agentless, written in golang.
|
||||
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)
|
||||
|
||||
@@ -23,14 +23,14 @@ Twitter: [@vuls_en](https://twitter.com/vuls_en)
|
||||
|
||||
----
|
||||
|
||||
# Abstract
|
||||
## Abstract
|
||||
|
||||
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 production environment, it is common for system administrator to choose not to use the automatic update option provided by package manager and to perform update manually.
|
||||
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.
|
||||
|
||||
- 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 installed in server.
|
||||
- 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.
|
||||
|
||||
Vuls is a tool created to solve the problems listed above. It has the following characteristics.
|
||||
@@ -38,134 +38,160 @@ Vuls is a tool created to solve the problems listed above. It has the following
|
||||
- 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.
|
||||
- Report is generated on regular basis using CRON or other methods. to manage vulnerability.
|
||||
- A report is generated on a regular basis using CRON or other methods. to manage vulnerability.
|
||||
|
||||

|
||||
|
||||
----
|
||||
|
||||
# Main Features
|
||||
## Main Features
|
||||
|
||||
## Scan for any vulnerabilities in Linux/FreeBSD Server
|
||||
### Scan for any vulnerabilities in Linux/FreeBSD Server
|
||||
|
||||
[Supports major Linux/FreeBSD](https://vuls.io/docs/en/supported-os.html)
|
||||
|
||||
- Alpine, Ubuntu, Debian, CentOS, Amazon Linux, RHEL, Oracle Linux, SUSE Enterprise Linux and Raspbian, FreeBSD
|
||||
- Cloud, on-premise, Docker
|
||||
- Alpine, Amazon Linux, CentOS, Alma Linux, Rocky Linux, Debian, Oracle Linux, Raspbian, RHEL, SUSE Enterprise Linux, and Ubuntu
|
||||
- FreeBSD
|
||||
- Cloud, on-premise, Running Docker Container
|
||||
|
||||
## High quality scan
|
||||
### High-quality scan
|
||||
|
||||
Vuls uses Multiple vulnerability databases
|
||||
- Vulnerability Database
|
||||
- [NVD](https://nvd.nist.gov/)
|
||||
- [JVN(Japanese)](http://jvndb.jvn.jp/apis/myjvn/)
|
||||
|
||||
- [NVD](https://nvd.nist.gov/)
|
||||
- [JVN(Japanese)](http://jvndb.jvn.jp/apis/myjvn/)
|
||||
- OVAL
|
||||
- [RedHat](https://www.redhat.com/security/data/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/)
|
||||
|
||||
- [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/)
|
||||
- Commands(yum, zypper, pkg-audit)
|
||||
- RHSA/ALAS/ELSA/FreeBSD-SA
|
||||
- [Exploit Database](https://www.exploit-db.com/)
|
||||
- [US-CERT](https://www.us-cert.gov/ncas/alerts)
|
||||
- [JPCERT](http://www.jpcert.or.jp/at/2019.html)
|
||||
- Changelog
|
||||
- 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/)
|
||||
- [Ubuntu CVE Tracker](https://people.canonical.com/~ubuntu-security/cve/)
|
||||
|
||||
## Fast scan and Deep scan
|
||||
- Commands(yum, zypper, pkg-audit)
|
||||
- RHSA / ALAS / ELSA / FreeBSD-SA
|
||||
- Changelog
|
||||
|
||||
- PoC, Exploit
|
||||
- [Exploit Database](https://www.exploit-db.com/)
|
||||
- [Metasploit-Framework modules](https://www.rapid7.com/db/?q=&type=metasploit)
|
||||
- [qazbnm456/awesome-cve-poc](https://github.com/qazbnm456/awesome-cve-poc)
|
||||
- [nomi-sec/PoC-in-GitHub](https://github.com/nomi-sec/PoC-in-GitHub)
|
||||
|
||||
- CERT
|
||||
- [US-CERT](https://www.us-cert.gov/ncas/alerts)
|
||||
- [JPCERT](http://www.jpcert.or.jp/at/2019.html)
|
||||
|
||||
- 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)
|
||||
|
||||
- WordPress
|
||||
- [wpscan](https://wpscan.com/api)
|
||||
|
||||
### 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. (Red Hat, CentOS, OracleLinux, Ubuntu, Debian)
|
||||
- Offline mode scan with no internet access. (CentOS, Alma Linux, Rocky Linux, 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 (RedHat, CentOS, Oracle Linux and Amazon Linux)
|
||||
- Detect processes affected by update using yum-ps (Amazon Linux, CentOS, Alma Linux, Rocky Linux, 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. (RedHat, CentOS, OracleLinux, Ubuntu, Debian)
|
||||
- Offline mode scan with no internet access. (CentOS, Alma Linux, Rocky Linux, Debian, Oracle Linux, Red Hat, and Ubuntu)
|
||||
|
||||
[Deep Scan](https://vuls.io/docs/en/architecture-deep-scan.html)
|
||||
### [Remote, Local scan mode, Server mode](https://vuls.io/docs/en/architecture-remote-local.html)
|
||||
|
||||
- Scan with root privilege
|
||||
- Parses the Changelog
|
||||
Changelog has a history of version changes. When a security issue is fixed, the relevant CVE ID is listed.
|
||||
By parsing the changelog and analysing the updates between the installed version of software on the server and the newest version of that software
|
||||
it's possible to create a list of all vulnerabilities that need to be fixed.
|
||||
- Sometimes load on the scan target server
|
||||
[Remote scan mode](https://vuls.io/docs/en/architecture-remote-scan.html)
|
||||
|
||||
## [Remote scan and Local scan](https://vuls.io/docs/en/architecture-remote-local.html)
|
||||
- User is required to only set up one machine that is connected to other target servers via SSH
|
||||
|
||||
[Remote Scan](https://vuls.io/docs/en/architecture-remote-scan.html)
|
||||
|
||||
- User is required to only setup one machine that is connected to other target servers via SSH
|
||||
|
||||
[Local Scan](https://vuls.io/docs/en/architecture-local-scan.html)
|
||||
[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.
|
||||
|
||||
## **Dynamic** Analysis
|
||||
[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 vulnerabilites of non-OS packages
|
||||
### Scan vulnerabilities of non-OS-packages
|
||||
|
||||
- [Common Platform Enumeration (CPE) based Scan](https://vuls.io/docs/en/usage-scan-non-os-packages.html#how-to-search-cpe-name-by-software-name)
|
||||
- NW equipment, middleware, programming language libraries and framework for vulnerability
|
||||
- Integrate with [GitHub Security Alerts](https://vuls.io/docs/en/usage-scan-non-os-packages.html#usage-integrate-with-github-security-alerts)
|
||||
- Integrate with [OWASP Dependency Check](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)
|
||||
- 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
|
||||
- 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 on terminal or Web UI ([VulsRepo](https://github.com/usiusi360/vulsrepo)).
|
||||
- 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
|
||||
## What Vuls Doesn't Do
|
||||
|
||||
- Vuls doesn't update the vulnerable packages.
|
||||
|
||||
----
|
||||
|
||||
# Document
|
||||
## Document
|
||||
|
||||
For more information such as Installation, Tutorial, Usage, visit [vuls.io](https://vuls.io/)
|
||||
For more information such as Installation, Tutorial, Usage, visit [vuls.io](https://vuls.io/)
|
||||
[日本語翻訳ドキュメント](https://vuls.io/ja/)
|
||||
|
||||
----
|
||||
|
||||
# Authors
|
||||
## Authors
|
||||
|
||||
kotakanbe ([@kotakanbe](https://twitter.com/kotakanbe)) created vuls and [these fine people](https://github.com/future-architect/vuls/graphs/contributors) have contributed.
|
||||
|
||||
----
|
||||
## Contribute
|
||||
|
||||
# Change Log
|
||||
|
||||
Please see [CHANGELOG](https://github.com/future-architect/vuls/blob/master/CHANGELOG.md).
|
||||
see [vulsdoc](https://vuls.io/docs/en/how-to-contribute.html)
|
||||
|
||||
----
|
||||
|
||||
# Stargazers over time
|
||||
## Stargazers over time
|
||||
|
||||
[](https://starcharts.herokuapp.com/future-architect/vuls)
|
||||
|
||||
-----;
|
||||
|
||||
# License
|
||||
## License
|
||||
|
||||
Please see [LICENSE](https://github.com/future-architect/vuls/blob/master/LICENSE).
|
||||
|
||||
2897
alert/alert_jp.go
2897
alert/alert_jp.go
File diff suppressed because it is too large
Load Diff
@@ -1,920 +0,0 @@
|
||||
package alert
|
||||
|
||||
// AlertDictEn has USCERT alerts
|
||||
var AlertDictEn = map[string]Alert{
|
||||
"https://www.us-cert.gov/ncas/alerts/TA08-352A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA08-352A",
|
||||
Title: `Microsoft Internet Explorer Data Binding Vulnerability`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA08-350A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA08-350A",
|
||||
Title: `Apple Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA08-344A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA08-344A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA08-340A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA08-340A",
|
||||
Title: `Sun Java Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA08-319A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA08-319A",
|
||||
Title: `Mozilla Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-132A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-132A",
|
||||
Title: `Microsoft PowerPoint Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-041A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-041A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-343A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-343A",
|
||||
Title: `Adobe Flash Vulnerabilities Affect Flash Player and Adobe AIR`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-218A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-218A",
|
||||
Title: `Apple Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-195A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-195A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-342A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-342A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-286B": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-286B",
|
||||
Title: `Adobe Reader and Acrobat Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-160B": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-160B",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-069A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-069A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-223A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-223A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-013A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-013A",
|
||||
Title: `Microsoft Updates for Multiple SMB Protocol Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-294A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-294A",
|
||||
Title: `Oracle Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-020A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-020A",
|
||||
Title: `Microsoft Windows Does Not Disable AutoRun Properly`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-133A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-133A",
|
||||
Title: `Apple Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-022A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-022A",
|
||||
Title: `Apple QuickTime Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-051A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-051A",
|
||||
Title: `Adobe Acrobat and Reader Vulnerability`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-015A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-015A",
|
||||
Title: `Oracle Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-251A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-251A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-209A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-209A",
|
||||
Title: `Microsoft Windows, Internet Explorer, and Active Template Library (ATL) Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-204A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-204A",
|
||||
Title: `Adobe Flash Vulnerability Affects Flash Player and Other Adobe Products`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-161A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-161A",
|
||||
Title: `Adobe Acrobat and Reader Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-133B": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-133B",
|
||||
Title: `Adobe Reader and Acrobat JavaScript Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-088A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-088A",
|
||||
Title: `Conficker Worm Targets Microsoft Windows Systems`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-314A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-314A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-105A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-105A",
|
||||
Title: `Oracle Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-104A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-104A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-286A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-286A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA09-187A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA09-187A",
|
||||
Title: `Microsoft Video ActiveX Control Vulnerability`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-238A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-238A",
|
||||
Title: `Microsoft Windows Insecurely Loads Dynamic Libraries`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-159B": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-159B",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-103B": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-103B",
|
||||
Title: `Oracle Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-021A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-021A",
|
||||
Title: `Microsoft Internet Explorer Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-012A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-012A",
|
||||
Title: `Oracle Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-313A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-313A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-285A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-285A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-263A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-263A",
|
||||
Title: `Adobe Flash Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-103C": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-103C",
|
||||
Title: `Adobe Reader and Acrobat Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-040A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-040A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-194B": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-194B",
|
||||
Title: `Oracle Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-194A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-194A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-131A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-131A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-068A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-068A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-348A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-348A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-257A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-257A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-231A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-231A",
|
||||
Title: `Adobe Reader and Acrobat Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-222A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-222A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-162A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-162A",
|
||||
Title: `Adobe Flash and AIR Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-159A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-159A",
|
||||
Title: `Adobe Flash, Reader, and Acrobat Vulnerability`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-089A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-089A",
|
||||
Title: `Microsoft Internet Explorer Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-013A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-013A",
|
||||
Title: `Adobe Reader and Acrobat Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-287A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-287A",
|
||||
Title: `Oracle Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-279A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-279A",
|
||||
Title: `Adobe Reader and Acrobat Affected by Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-223A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-223A",
|
||||
Title: `Adobe Flash and AIR Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA10-012B": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA10-012B",
|
||||
Title: `Microsoft Windows EOT Font and Adobe Flash Player 6 Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-165A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-165A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-067A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-067A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-039A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-039A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-222A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-222A",
|
||||
Title: `Adobe Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-193A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-193A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-201A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-201A",
|
||||
Title: `Oracle Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-166A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-166A",
|
||||
Title: `Adobe Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-130A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-130A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-312A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-312A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-286A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-286A",
|
||||
Title: `Apple Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-350A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-350A",
|
||||
Title: `Adobe Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-221A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-221A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-256A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-256A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-200A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-200A",
|
||||
Title: `Security Recommendations to Prevent Cyber Intrusions`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-102A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-102A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-011A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-011A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-347A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-347A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA11-284A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA11-284A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-262A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-262A",
|
||||
Title: `Microsoft Security Advisory for Internet Explorer Exploit`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-240A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-240A",
|
||||
Title: `Oracle Java 7 Security Manager Bypass Vulnerability`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-227A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-227A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-129A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-129A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-101B": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-101B",
|
||||
Title: `Adobe Reader and Acrobat Security Updates and Architectural Improvements`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-010A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-010A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-006A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-006A",
|
||||
Title: `Wi-Fi Protected Setup (WPS) Vulnerable to Brute-Force Attack`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-265A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-265A",
|
||||
Title: `Microsoft Releases Patch for Internet Explorer Exploit`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-255A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-255A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-251A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-251A",
|
||||
Title: `Microsoft Update For Minimum Certificate Key Length`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-174A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-174A",
|
||||
Title: `Microsoft XML Core Services Attack Activity`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-164A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-164A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-101A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-101A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-318A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-318A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-283A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-283A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-346A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-346A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-192A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-192A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-073A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-073A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-045A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-045A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA12-024A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA12-024A",
|
||||
Title: `"Anonymous" DDoS Activity`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-134A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-134A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-043B": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-043B",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-008A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-008A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-051A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-051A",
|
||||
Title: `Oracle Java Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-043A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-043A",
|
||||
Title: `Adobe Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-225A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-225A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-207A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-207A",
|
||||
Title: `Risks of Using the Intelligent Platform Management Interface (IPMI)`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-141A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-141A",
|
||||
Title: `Washington, DC Radio Station Web Site Compromises`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-175A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-175A",
|
||||
Title: `Risks of Default Passwords on the Internet`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-169A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-169A",
|
||||
Title: `Oracle Releases Updates for Javadoc and Other Java SE Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-168A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-168A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-100A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-100A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-088A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-088A",
|
||||
Title: `DNS Amplification Attacks`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-317A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-317A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-309A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-309A",
|
||||
Title: `CryptoLocker Ransomware Infections`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-288A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-288A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-064A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-064A",
|
||||
Title: `Oracle Java Contains Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-032A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-032A",
|
||||
Title: `Oracle Java Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-024A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-024A",
|
||||
Title: `Content Management Systems Security and Associated Risks`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-107A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-107A",
|
||||
Title: `Oracle Has Released Multiple Updates for Java SE`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-071A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-071A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-015A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-015A",
|
||||
Title: `Microsoft Releases Update for Internet Explorer Vulnerability CVE-2012-4792`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-010A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-010A",
|
||||
Title: `Oracle Java 7 Security Manager Bypass Vulnerability`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-253A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-253A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-193A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-193A",
|
||||
Title: `Exploit Tool Targets Vulnerabilities in McAfee ePolicy Orchestrator (ePO)`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA13-190A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA13-190A",
|
||||
Title: `Microsoft Updates for Multiple Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-323A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-323A",
|
||||
Title: `Microsoft Windows Kerberos KDC Remote Privilege Escalation Vulnerability `,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-300A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-300A",
|
||||
Title: `Phishing Campaign Linked with “Dyre” Banking Malware`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-295A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-295A",
|
||||
Title: `Crypto Ransomware`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-318B": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-318B",
|
||||
Title: `Microsoft Windows OLE Automation Array Remote Code Execution Vulnerability `,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-317A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-317A",
|
||||
Title: `Apple iOS 'Masque Attack' Technique`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-290A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-290A",
|
||||
Title: `SSL 3.0 Protocol Vulnerability and POODLE Attack`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-017A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-017A",
|
||||
Title: `UDP-Based Amplification Attacks`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-002A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-002A",
|
||||
Title: `Malware Targeting Point of Sale Systems`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-318A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-318A",
|
||||
Title: `Microsoft Secure Channel (Schannel) Vulnerability (CVE-2014-6321) `,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-310A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-310A",
|
||||
Title: `Microsoft Ending Support for Windows Server 2003 Operating System`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-268A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-268A",
|
||||
Title: `GNU Bourne-Again Shell (Bash) ‘Shellshock’ Vulnerability (CVE-2014-6271, CVE-2014-7169, CVE-2014-7186, CVE-2014-7187, CVE-2014-6277 and CVE 2014-6278) `,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-098A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-098A",
|
||||
Title: `OpenSSL 'Heartbleed' vulnerability (CVE-2014-0160)`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-353A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-353A",
|
||||
Title: `Targeted Destructive Malware`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-329A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-329A",
|
||||
Title: `Regin Malware`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-212A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-212A",
|
||||
Title: `Backoff Point-of-Sale Malware`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-150A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-150A",
|
||||
Title: `GameOver Zeus P2P Malware`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA14-013A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA14-013A",
|
||||
Title: `NTP Amplification Attacks Using CVE-2013-5211`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA15-195A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA15-195A",
|
||||
Title: `Adobe Flash and Microsoft Windows Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA15-337A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA15-337A",
|
||||
Title: `Dorkbot`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA15-240A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA15-240A",
|
||||
Title: `Controlling Outbound DNS Access`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA15-213A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA15-213A",
|
||||
Title: `Recent Email Phishing Campaigns – Mitigation and Response Recommendations`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA15-120A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA15-120A",
|
||||
Title: `Securing End-to-End Communications`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA15-119A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA15-119A",
|
||||
Title: `Top 30 Targeted High Risk Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA15-105A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA15-105A",
|
||||
Title: `Simda Botnet`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA15-103A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA15-103A",
|
||||
Title: `DNS Zone Transfer AXFR Requests May Leak Domain Information`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA15-098A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA15-098A",
|
||||
Title: `AAEH`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA15-314A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA15-314A",
|
||||
Title: `Compromised Web Servers and Web Shells - Threat Awareness and Guidance `,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA15-286A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA15-286A",
|
||||
Title: `Dridex P2P Malware`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA15-051A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA15-051A",
|
||||
Title: `Lenovo Superfish Adware Vulnerable to HTTPS Spoofing`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA16-187A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA16-187A",
|
||||
Title: `Symantec and Norton Security Products Contain Critical Vulnerabilities`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA16-144A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA16-144A",
|
||||
Title: `WPAD Name Collision Vulnerability`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA16-132A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA16-132A",
|
||||
Title: `Exploitation of SAP Business Applications`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA16-105A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA16-105A",
|
||||
Title: `Apple Ends Support for QuickTime for Windows; New Vulnerabilities Announced`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA16-091A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA16-091A",
|
||||
Title: `Ransomware and Recent Variants`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA16-336A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA16-336A",
|
||||
Title: `Avalanche (crimeware-as-a-service infrastructure)`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA16-288A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA16-288A",
|
||||
Title: `Heightened DDoS Threat Posed by Mirai and Other Botnets`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA16-250A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA16-250A",
|
||||
Title: `The Increasing Threat to Network Infrastructure Devices and Recommended Mitigations`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA17-117A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA17-117A",
|
||||
Title: `Intrusions Affecting Multiple Victims Across Multiple Sectors`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA17-318B": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA17-318B",
|
||||
Title: `HIDDEN COBRA – North Korean Trojan: Volgmer`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA17-318A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA17-318A",
|
||||
Title: `HIDDEN COBRA – North Korean Remote Administration Tool: FALLCHILL`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA17-181A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA17-181A",
|
||||
Title: `Petya Ransomware `,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA17-132A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA17-132A",
|
||||
Title: `Indicators Associated With WannaCry Ransomware`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA17-075A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA17-075A",
|
||||
Title: `HTTPS Interception Weakens TLS Security`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA17-293A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA17-293A",
|
||||
Title: `Advanced Persistent Threat Activity Targeting Energy and Other Critical Infrastructure Sectors`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA17-164A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA17-164A",
|
||||
Title: `HIDDEN COBRA – North Korea’s DDoS Botnet Infrastructure`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA17-163A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA17-163A",
|
||||
Title: `CrashOverride Malware`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA17-156A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA17-156A",
|
||||
Title: `Reducing the Risk of SNMP Abuse`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA18-141A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA18-141A",
|
||||
Title: `Side-Channel Vulnerability Variants 3a and 4`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA18-086A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA18-086A",
|
||||
Title: `Brute Force Attacks Conducted by Cyber Actors `,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA18-004A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA18-004A",
|
||||
Title: `Meltdown and Spectre Side-Channel Vulnerability Guidance`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA18-331A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA18-331A",
|
||||
Title: `3ve – Major Online Ad Fraud Operation`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/AA18-284A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/AA18-284A",
|
||||
Title: `Publicly Available Tools Seen in Cyber Incidents Worldwide`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA18-276B": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA18-276B",
|
||||
Title: `Advanced Persistent Threat Activity Exploiting Managed Service Providers`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA18-275A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA18-275A",
|
||||
Title: `HIDDEN COBRA – FASTCash Campaign`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA18-201A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA18-201A",
|
||||
Title: `Emotet Malware`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA18-276A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA18-276A",
|
||||
Title: `Using Rigorous Credential Control to Mitigate Trusted Network Exploitation`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA18-149A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA18-149A",
|
||||
Title: `HIDDEN COBRA – Joanap Backdoor Trojan and Brambul Server Message Block Worm`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA18-145A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA18-145A",
|
||||
Title: `Cyber Actors Target Home and Office Routers and Networked Devices Worldwide`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA18-106A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA18-106A",
|
||||
Title: `Russian State-Sponsored Cyber Actors Targeting Network Infrastructure Devices`,
|
||||
Team: "us",
|
||||
},
|
||||
"https://www.us-cert.gov/ncas/alerts/TA18-074A": {
|
||||
URL: "https://www.us-cert.gov/ncas/alerts/TA18-074A",
|
||||
Title: `Russian Government Cyber Activity Targeting Energy and Other Critical Infrastructure Sectors`,
|
||||
Team: "us",
|
||||
},
|
||||
}
|
||||
534
alert/cve_jp.go
534
alert/cve_jp.go
@@ -1,534 +0,0 @@
|
||||
package alert
|
||||
|
||||
// CveDictJa has CVE-ID key which included JPCERT alerts
|
||||
var CveDictJa = map[string][]string{
|
||||
"CVE-2006-0003": {"https://www.jpcert.or.jp/at/2007/at070016.html"},
|
||||
"CVE-2006-0005": {"https://www.jpcert.or.jp/at/2007/at070016.html"},
|
||||
"CVE-2006-1173": {"https://www.jpcert.or.jp/at/2006/at060008.html"},
|
||||
"CVE-2006-3014": {"https://www.jpcert.or.jp/at/2006/at060009.html"},
|
||||
"CVE-2006-3059": {"https://www.jpcert.or.jp/at/2006/at060009.html"},
|
||||
"CVE-2006-3086": {"https://www.jpcert.or.jp/at/2006/at060009.html"},
|
||||
"CVE-2006-3643": {"https://www.jpcert.or.jp/at/2007/at070016.html"},
|
||||
"CVE-2006-3730": {"https://www.jpcert.or.jp/at/2007/at070016.html"},
|
||||
"CVE-2006-3877": {"https://www.jpcert.or.jp/at/2007/at070005.html"},
|
||||
"CVE-2006-5198": {"https://www.jpcert.or.jp/at/2007/at070016.html"},
|
||||
"CVE-2006-5745": {"https://www.jpcert.or.jp/at/2007/at070016.html"},
|
||||
"CVE-2007-0015": {"https://www.jpcert.or.jp/at/2007/at070016.html"},
|
||||
"CVE-2007-0038": {"https://www.jpcert.or.jp/at/2007/at070016.html"},
|
||||
"CVE-2008-4609": {"https://www.jpcert.or.jp/at/2009/at090019.html"},
|
||||
"CVE-2010-0886": {"https://www.jpcert.or.jp/at/2010/at100010.html"},
|
||||
"CVE-2010-0887": {"https://www.jpcert.or.jp/at/2010/at100010.html"},
|
||||
"CVE-2011-1910": {"https://www.jpcert.or.jp/at/2011/at110014.html"},
|
||||
"CVE-2011-2444": {"https://www.jpcert.or.jp/at/2011/at110026.html"},
|
||||
"CVE-2011-2462": {"https://www.jpcert.or.jp/at/2011/at110034.html"},
|
||||
"CVE-2011-2465": {"https://www.jpcert.or.jp/at/2011/at110019.html"},
|
||||
"CVE-2011-3192": {"https://www.jpcert.or.jp/at/2011/at110023.html"},
|
||||
"CVE-2011-3348": {"https://www.jpcert.or.jp/at/2011/at110023.html"},
|
||||
"CVE-2011-3544": {"https://www.jpcert.or.jp/at/2011/at110032.html"},
|
||||
"CVE-2011-4313": {"https://www.jpcert.or.jp/at/2011/at110031.html"},
|
||||
"CVE-2012-0002": {"https://www.jpcert.or.jp/at/2012/at120009.html"},
|
||||
"CVE-2012-0507": {"https://www.jpcert.or.jp/at/2012/at120010.html"},
|
||||
"CVE-2012-0767": {"https://www.jpcert.or.jp/at/2012/at120006.html"},
|
||||
"CVE-2012-0779": {"https://www.jpcert.or.jp/at/2012/at120014.html"},
|
||||
"CVE-2012-0830": {"https://www.jpcert.or.jp/at/2012/at120004.html"},
|
||||
"CVE-2012-2311": {"https://www.jpcert.or.jp/at/2012/at120016.html"},
|
||||
"CVE-2012-4244": {"https://www.jpcert.or.jp/at/2012/at120029.html"},
|
||||
"CVE-2012-4681": {"https://www.jpcert.or.jp/at/2012/at120028.html"},
|
||||
"CVE-2012-4969": {"https://www.jpcert.or.jp/at/2012/at120030.html"},
|
||||
"CVE-2012-5166": {"https://www.jpcert.or.jp/at/2012/at120033.html"},
|
||||
"CVE-2013-0422": {"https://www.jpcert.or.jp/at/2013/at130004.html"},
|
||||
"CVE-2013-1493": {"https://www.jpcert.or.jp/at/2013/at130014.html"},
|
||||
"CVE-2013-2266": {"https://www.jpcert.or.jp/at/2013/at130017.html"},
|
||||
"CVE-2013-2494": {"https://www.jpcert.or.jp/at/2013/at130017.html"},
|
||||
"CVE-2013-3893": {"https://www.jpcert.or.jp/at/2013/at130040.html", "https://www.jpcert.or.jp/at/2013/at130041.html"},
|
||||
"CVE-2013-3906": {"https://www.jpcert.or.jp/at/2013/at130044.html"},
|
||||
"CVE-2013-3918": {"https://www.jpcert.or.jp/at/2013/at130045.html"},
|
||||
"CVE-2013-3919": {"https://www.jpcert.or.jp/at/2013/at130026.html"},
|
||||
"CVE-2013-4854": {"https://www.jpcert.or.jp/at/2013/at130034.html"},
|
||||
"CVE-2014-0050": {"https://www.jpcert.or.jp/at/2014/at140007.html"},
|
||||
"CVE-2014-0160": {"https://www.jpcert.or.jp/at/2014/at140013.html"},
|
||||
"CVE-2014-0322": {"https://www.jpcert.or.jp/at/2014/at140009.html"},
|
||||
"CVE-2014-1776": {"https://www.jpcert.or.jp/at/2014/at140018.html", "https://www.jpcert.or.jp/at/2014/at140020.html"},
|
||||
"CVE-2014-3383": {"https://www.jpcert.or.jp/at/2015/at150021.html"},
|
||||
"CVE-2014-3859": {"https://www.jpcert.or.jp/at/2014/at140027.html"},
|
||||
"CVE-2014-4114": {"https://www.jpcert.or.jp/at/2014/at140039.html"},
|
||||
"CVE-2014-6271": {"https://www.jpcert.or.jp/at/2014/at140037.html", "https://www.jpcert.or.jp/at/2014/at140038.html"},
|
||||
"CVE-2014-6277": {"https://www.jpcert.or.jp/at/2014/at140037.html"},
|
||||
"CVE-2014-6278": {"https://www.jpcert.or.jp/at/2014/at140037.html"},
|
||||
"CVE-2014-6324": {"https://www.jpcert.or.jp/at/2014/at140048.html"},
|
||||
"CVE-2014-6332": {"https://www.jpcert.or.jp/at/2015/at150015.html"},
|
||||
"CVE-2014-6352": {"https://www.jpcert.or.jp/at/2014/at140043.html"},
|
||||
"CVE-2014-7169": {"https://www.jpcert.or.jp/at/2014/at140037.html"},
|
||||
"CVE-2014-7186": {"https://www.jpcert.or.jp/at/2014/at140037.html"},
|
||||
"CVE-2014-7187": {"https://www.jpcert.or.jp/at/2014/at140037.html"},
|
||||
"CVE-2014-8361": {"https://www.jpcert.or.jp/at/2017/at170049.html"},
|
||||
"CVE-2014-8500": {"https://www.jpcert.or.jp/at/2014/at140050.html"},
|
||||
"CVE-2014-9163": {"https://www.jpcert.or.jp/at/2014/at140052.html"},
|
||||
"CVE-2015-0313": {"https://www.jpcert.or.jp/at/2015/at150015.html"},
|
||||
"CVE-2015-1769": {"https://www.jpcert.or.jp/at/2015/at150028.html"},
|
||||
"CVE-2015-5119": {"https://www.jpcert.or.jp/at/2015/at150019.html"},
|
||||
"CVE-2015-5122": {"https://www.jpcert.or.jp/at/2015/at150020.html"},
|
||||
"CVE-2015-5123": {"https://www.jpcert.or.jp/at/2015/at150020.html"},
|
||||
"CVE-2015-5477": {"https://www.jpcert.or.jp/at/2015/at150027.html"},
|
||||
"CVE-2015-5986": {"https://www.jpcert.or.jp/at/2015/at150031.html"},
|
||||
"CVE-2015-6835": {"https://www.jpcert.or.jp/at/2016/at160036.html"},
|
||||
"CVE-2015-7547": {"https://www.jpcert.or.jp/at/2016/at160009.html"},
|
||||
"CVE-2015-7645": {"https://www.jpcert.or.jp/at/2015/at150036.html", "https://www.jpcert.or.jp/at/2015/at150037.html"},
|
||||
"CVE-2015-8000": {"https://www.jpcert.or.jp/at/2015/at150043.html"},
|
||||
"CVE-2015-8461": {"https://www.jpcert.or.jp/at/2015/at150043.html"},
|
||||
"CVE-2015-8562": {"https://www.jpcert.or.jp/at/2016/at160036.html"},
|
||||
"CVE-2015-8651": {"https://www.jpcert.or.jp/at/2016/at160001.html"},
|
||||
"CVE-2015-8704": {"https://www.jpcert.or.jp/at/2016/at160006.html"},
|
||||
"CVE-2015-8705": {"https://www.jpcert.or.jp/at/2016/at160006.html"},
|
||||
"CVE-2016-0189": {"https://www.jpcert.or.jp/at/2016/at160022.html"},
|
||||
"CVE-2016-0636": {"https://www.jpcert.or.jp/at/2016/at160015.html"},
|
||||
"CVE-2016-0800": {"https://www.jpcert.or.jp/at/2016/at160010.html"},
|
||||
"CVE-2016-1000109": {"https://www.jpcert.or.jp/at/2016/at160031.html"},
|
||||
"CVE-2016-1000110": {"https://www.jpcert.or.jp/at/2016/at160031.html"},
|
||||
"CVE-2016-1010": {"https://www.jpcert.or.jp/at/2016/at160014.html"},
|
||||
"CVE-2016-1019": {"https://www.jpcert.or.jp/at/2016/at160016.html"},
|
||||
"CVE-2016-1204": {"https://www.jpcert.or.jp/at/2016/at160019.html"},
|
||||
"CVE-2016-1286": {"https://www.jpcert.or.jp/at/2016/at160013.html", "https://www.jpcert.or.jp/at/2016/at160037.html"},
|
||||
"CVE-2016-2776": {"https://www.jpcert.or.jp/at/2016/at160037.html"},
|
||||
"CVE-2016-3081": {"https://www.jpcert.or.jp/at/2016/at160020.html"},
|
||||
"CVE-2016-3227": {"https://www.jpcert.or.jp/at/2016/at160025.html"},
|
||||
"CVE-2016-3714": {"https://www.jpcert.or.jp/at/2016/at160021.html"},
|
||||
"CVE-2016-3715": {"https://www.jpcert.or.jp/at/2016/at160021.html"},
|
||||
"CVE-2016-3716": {"https://www.jpcert.or.jp/at/2016/at160021.html"},
|
||||
"CVE-2016-3717": {"https://www.jpcert.or.jp/at/2016/at160021.html"},
|
||||
"CVE-2016-3718": {"https://www.jpcert.or.jp/at/2016/at160021.html"},
|
||||
"CVE-2016-4117": {"https://www.jpcert.or.jp/at/2016/at160024.html"},
|
||||
"CVE-2016-4171": {"https://www.jpcert.or.jp/at/2016/at160026.html"},
|
||||
"CVE-2016-4438": {"https://www.jpcert.or.jp/at/2016/at160027.html"},
|
||||
"CVE-2016-5385": {"https://www.jpcert.or.jp/at/2016/at160031.html"},
|
||||
"CVE-2016-5386": {"https://www.jpcert.or.jp/at/2016/at160031.html"},
|
||||
"CVE-2016-5387": {"https://www.jpcert.or.jp/at/2016/at160031.html"},
|
||||
"CVE-2016-5388": {"https://www.jpcert.or.jp/at/2016/at160031.html"},
|
||||
"CVE-2016-6307": {"https://www.jpcert.or.jp/at/2016/at160038.html"},
|
||||
"CVE-2016-6309": {"https://www.jpcert.or.jp/at/2016/at160038.html"},
|
||||
"CVE-2016-7189": {"https://www.jpcert.or.jp/at/2016/at160039.html"},
|
||||
"CVE-2016-7836": {"https://www.jpcert.or.jp/at/2016/at160051.html", "https://www.jpcert.or.jp/at/2017/at170023.html"},
|
||||
"CVE-2016-7855": {"https://www.jpcert.or.jp/at/2016/at160039.html", "https://www.jpcert.or.jp/at/2016/at160043.html"},
|
||||
"CVE-2016-7892": {"https://www.jpcert.or.jp/at/2016/at160048.html", "https://www.jpcert.or.jp/at/2016/at160049.html"},
|
||||
"CVE-2016-8864": {"https://www.jpcert.or.jp/at/2016/at160044.html"},
|
||||
"CVE-2016-9131": {"https://www.jpcert.or.jp/at/2017/at170004.html"},
|
||||
"CVE-2016-9147": {"https://www.jpcert.or.jp/at/2017/at170004.html"},
|
||||
"CVE-2016-9444": {"https://www.jpcert.or.jp/at/2017/at170004.html"},
|
||||
"CVE-2016-9778": {"https://www.jpcert.or.jp/at/2017/at170004.html"},
|
||||
"CVE-2017-0093": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0106": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0145": {"https://www.jpcert.or.jp/at/2017/at170020.html"},
|
||||
"CVE-2017-0158": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0160": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0161": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-0162": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0163": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0180": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0181": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0199": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0200": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0201": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0202": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0205": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0210": {"https://www.jpcert.or.jp/at/2017/at170015.html"},
|
||||
"CVE-2017-0221": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0222": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0224": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0227": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0228": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0229": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0235": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0236": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0240": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0250": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-0261": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0263": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0266": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0272": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0277": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0278": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0279": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0283": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-0290": {"https://www.jpcert.or.jp/at/2017/at170019.html"},
|
||||
"CVE-2017-0291": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-0292": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-0293": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-0294": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-0781": {"https://www.jpcert.or.jp/at/2017/at170037.html"},
|
||||
"CVE-2017-0782": {"https://www.jpcert.or.jp/at/2017/at170037.html"},
|
||||
"CVE-2017-0783": {"https://www.jpcert.or.jp/at/2017/at170037.html"},
|
||||
"CVE-2017-0785": {"https://www.jpcert.or.jp/at/2017/at170037.html"},
|
||||
"CVE-2017-1000250": {"https://www.jpcert.or.jp/at/2017/at170037.html"},
|
||||
"CVE-2017-1000251": {"https://www.jpcert.or.jp/at/2017/at170037.html"},
|
||||
"CVE-2017-10271": {"https://www.jpcert.or.jp/at/2018/at180004.html"},
|
||||
"CVE-2017-10845": {"https://www.jpcert.or.jp/at/2017/at170034.html"},
|
||||
"CVE-2017-10846": {"https://www.jpcert.or.jp/at/2017/at170034.html"},
|
||||
"CVE-2017-11223": {"https://www.jpcert.or.jp/at/2017/at170031.html"},
|
||||
"CVE-2017-11292": {"https://www.jpcert.or.jp/at/2017/at170040.html"},
|
||||
"CVE-2017-11762": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11763": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11764": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-11766": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-11771": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11779": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11792": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11793": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11796": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11798": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11799": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11800": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11802": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11804": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11805": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11806": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11807": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11808": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11809": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11810": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11811": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11812": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11813": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11819": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11821": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11822": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11826": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-11836": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11837": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11838": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11839": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11840": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11841": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11843": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11845": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11846": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11855": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11856": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11858": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11861": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11862": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11866": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11869": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11870": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11871": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11873": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11882": {"https://www.jpcert.or.jp/at/2017/at170044.html"},
|
||||
"CVE-2017-11886": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11888": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11889": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11890": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11893": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11894": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11895": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11901": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11903": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11905": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11907": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11908": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11909": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11910": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11911": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11912": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11914": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11918": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11930": {"https://www.jpcert.or.jp/at/2017/at170048.html"},
|
||||
"CVE-2017-11937": {"https://www.jpcert.or.jp/at/2017/at170046.html"},
|
||||
"CVE-2017-12615": {"https://www.jpcert.or.jp/at/2017/at170038.html"},
|
||||
"CVE-2017-12616": {"https://www.jpcert.or.jp/at/2017/at170038.html"},
|
||||
"CVE-2017-12617": {"https://www.jpcert.or.jp/at/2017/at170038.html"},
|
||||
"CVE-2017-13872": {"https://www.jpcert.or.jp/at/2017/at170045.html"},
|
||||
"CVE-2017-14315": {"https://www.jpcert.or.jp/at/2017/at170037.html"},
|
||||
"CVE-2017-3135": {"https://www.jpcert.or.jp/at/2017/at170007.html"},
|
||||
"CVE-2017-3136": {"https://www.jpcert.or.jp/at/2017/at170016.html"},
|
||||
"CVE-2017-3137": {"https://www.jpcert.or.jp/at/2017/at170016.html"},
|
||||
"CVE-2017-3138": {"https://www.jpcert.or.jp/at/2017/at170016.html"},
|
||||
"CVE-2017-3142": {"https://www.jpcert.or.jp/at/2017/at170024.html"},
|
||||
"CVE-2017-3143": {"https://www.jpcert.or.jp/at/2017/at170024.html"},
|
||||
"CVE-2017-3145": {"https://www.jpcert.or.jp/at/2018/at180005.html"},
|
||||
"CVE-2017-5638": {"https://www.jpcert.or.jp/at/2017/at170009.html"},
|
||||
"CVE-2017-6753": {"https://www.jpcert.or.jp/at/2017/at170028.html"},
|
||||
"CVE-2017-8463": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8464": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-8496": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-8497": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-8499": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-8517": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-8520": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-8522": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-8524": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-8527": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-8528": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-8543": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-8548": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-8549": {"https://www.jpcert.or.jp/at/2017/at170022.html"},
|
||||
"CVE-2017-8584": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8589": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8591": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8594": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8595": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8596": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8598": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8601": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8603": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8604": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8605": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8606": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8607": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8608": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8609": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8610": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8617": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8618": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8619": {"https://www.jpcert.or.jp/at/2017/at170027.html"},
|
||||
"CVE-2017-8620": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8622": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8628": {"https://www.jpcert.or.jp/at/2017/at170037.html"},
|
||||
"CVE-2017-8634": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8635": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8636": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8638": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8639": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8640": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8641": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8645": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8646": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8647": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8649": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8653": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8655": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8656": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8657": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8660": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8661": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8669": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8670": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8671": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8672": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8674": {"https://www.jpcert.or.jp/at/2017/at170032.html"},
|
||||
"CVE-2017-8676": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8682": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8686": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8696": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8727": {"https://www.jpcert.or.jp/at/2017/at170039.html"},
|
||||
"CVE-2017-8728": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8729": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8731": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8734": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8737": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8738": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8740": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8741": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8747": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8748": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8749": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8750": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8751": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8752": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8753": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8755": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8756": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8757": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-8759": {"https://www.jpcert.or.jp/at/2017/at170036.html"},
|
||||
"CVE-2017-9791": {"https://www.jpcert.or.jp/at/2017/at170025.html"},
|
||||
"CVE-2017-9805": {"https://www.jpcert.or.jp/at/2017/at170033.html"},
|
||||
"CVE-2018-0171": {"https://www.jpcert.or.jp/at/2018/at180013.html"},
|
||||
"CVE-2018-0758": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0762": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0763": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-0767": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0769": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0770": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0772": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0773": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0774": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0775": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0776": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0777": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0778": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0780": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0781": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0797": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0800": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0802": {"https://www.jpcert.or.jp/at/2018/at180002.html"},
|
||||
"CVE-2018-0825": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-0834": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-0835": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-0837": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-0838": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-0840": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-0852": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-0856": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-0857": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-0859": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-0860": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-0861": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-0870": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-0872": {"https://www.jpcert.or.jp/at/2018/at180011.html"},
|
||||
"CVE-2018-0874": {"https://www.jpcert.or.jp/at/2018/at180011.html"},
|
||||
"CVE-2018-0876": {"https://www.jpcert.or.jp/at/2018/at180011.html"},
|
||||
"CVE-2018-0889": {"https://www.jpcert.or.jp/at/2018/at180011.html"},
|
||||
"CVE-2018-0893": {"https://www.jpcert.or.jp/at/2018/at180011.html"},
|
||||
"CVE-2018-0930": {"https://www.jpcert.or.jp/at/2018/at180011.html"},
|
||||
"CVE-2018-0931": {"https://www.jpcert.or.jp/at/2018/at180011.html"},
|
||||
"CVE-2018-0932": {"https://www.jpcert.or.jp/at/2018/at180011.html"},
|
||||
"CVE-2018-0933": {"https://www.jpcert.or.jp/at/2018/at180011.html"},
|
||||
"CVE-2018-0934": {"https://www.jpcert.or.jp/at/2018/at180011.html"},
|
||||
"CVE-2018-0936": {"https://www.jpcert.or.jp/at/2018/at180011.html"},
|
||||
"CVE-2018-0937": {"https://www.jpcert.or.jp/at/2018/at180011.html"},
|
||||
"CVE-2018-0939": {"https://www.jpcert.or.jp/at/2018/at180011.html"},
|
||||
"CVE-2018-0943": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-0945": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-0946": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-0950": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-0951": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-0953": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-0954": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-0955": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-0959": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-0961": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-0965": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-0979": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-0980": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-0981": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-0988": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-0990": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-0991": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-0993": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-0994": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-0995": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-0996": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-1000": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-1004": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-1010": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-1012": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-1013": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-1015": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-1016": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-1018": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-1019": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-1020": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-1022": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-1023": {"https://www.jpcert.or.jp/at/2018/at180016.html"},
|
||||
"CVE-2018-11776": {"https://www.jpcert.or.jp/at/2018/at180036.html"},
|
||||
"CVE-2018-1270": {"https://www.jpcert.or.jp/at/2018/at180014.html"},
|
||||
"CVE-2018-1271": {"https://www.jpcert.or.jp/at/2018/at180014.html"},
|
||||
"CVE-2018-1272": {"https://www.jpcert.or.jp/at/2018/at180014.html"},
|
||||
"CVE-2018-1273": {"https://www.jpcert.or.jp/at/2018/at180017.html"},
|
||||
"CVE-2018-1274": {"https://www.jpcert.or.jp/at/2018/at180017.html"},
|
||||
"CVE-2018-1275": {"https://www.jpcert.or.jp/at/2018/at180014.html"},
|
||||
"CVE-2018-12794": {"https://www.jpcert.or.jp/at/2018/at180039.html"},
|
||||
"CVE-2018-1336": {"https://www.jpcert.or.jp/at/2018/at180030.html"},
|
||||
"CVE-2018-15442": {"https://www.jpcert.or.jp/at/2018/at180043.html"},
|
||||
"CVE-2018-15979": {"https://www.jpcert.or.jp/at/2018/at180045.html"},
|
||||
"CVE-2018-2628": {"https://www.jpcert.or.jp/at/2018/at180029.html"},
|
||||
"CVE-2018-2893": {"https://www.jpcert.or.jp/at/2018/at180029.html"},
|
||||
"CVE-2018-2894": {"https://www.jpcert.or.jp/at/2018/at180029.html"},
|
||||
"CVE-2018-2933": {"https://www.jpcert.or.jp/at/2018/at180029.html"},
|
||||
"CVE-2018-2983": {"https://www.jpcert.or.jp/at/2018/at180029.html"},
|
||||
"CVE-2018-2998": {"https://www.jpcert.or.jp/at/2018/at180029.html"},
|
||||
"CVE-2018-4877": {"https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-4878": {"https://www.jpcert.or.jp/at/2018/at180006.html", "https://www.jpcert.or.jp/at/2018/at180008.html"},
|
||||
"CVE-2018-4945": {"https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-5000": {"https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-5001": {"https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-5002": {"https://www.jpcert.or.jp/at/2018/at180024.html", "https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-5740": {"https://www.jpcert.or.jp/at/2018/at180031.html"},
|
||||
"CVE-2018-7600": {"https://www.jpcert.or.jp/at/2018/at180012.html"},
|
||||
"CVE-2018-7602": {"https://www.jpcert.or.jp/at/2018/at180019.html"},
|
||||
"CVE-2018-8034": {"https://www.jpcert.or.jp/at/2018/at180030.html"},
|
||||
"CVE-2018-8037": {"https://www.jpcert.or.jp/at/2018/at180030.html"},
|
||||
"CVE-2018-8110": {"https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-8111": {"https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-8114": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-8120": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-8122": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-8128": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-8130": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-8133": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-8137": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-8139": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-8154": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-8174": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-8178": {"https://www.jpcert.or.jp/at/2018/at180021.html"},
|
||||
"CVE-2018-8213": {"https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-8225": {"https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-8229": {"https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-8231": {"https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-8236": {"https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-8242": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8249": {"https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-8251": {"https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-8262": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8266": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8267": {"https://www.jpcert.or.jp/at/2018/at180025.html"},
|
||||
"CVE-2018-8273": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8274": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8275": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8279": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8280": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8286": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8288": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8290": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8291": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8294": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8296": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8301": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8302": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8324": {"https://www.jpcert.or.jp/at/2018/at180028.html"},
|
||||
"CVE-2018-8332": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8344": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8345": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8350": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8355": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8367": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8371": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8372": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8373": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8377": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8380": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8381": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8385": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8387": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8390": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8397": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8403": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8414": {"https://www.jpcert.or.jp/at/2018/at180034.html"},
|
||||
"CVE-2018-8420": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8421": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8439": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8440": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8447": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8453": {"https://www.jpcert.or.jp/at/2018/at180041.html"},
|
||||
"CVE-2018-8456": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8457": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8459": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8460": {"https://www.jpcert.or.jp/at/2018/at180041.html"},
|
||||
"CVE-2018-8461": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8464": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8465": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8466": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8467": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8473": {"https://www.jpcert.or.jp/at/2018/at180041.html"},
|
||||
"CVE-2018-8475": {"https://www.jpcert.or.jp/at/2018/at180038.html"},
|
||||
"CVE-2018-8476": {"https://www.jpcert.or.jp/at/2018/at180046.html"},
|
||||
"CVE-2018-8489": {"https://www.jpcert.or.jp/at/2018/at180041.html"},
|
||||
"CVE-2018-8490": {"https://www.jpcert.or.jp/at/2018/at180041.html"},
|
||||
"CVE-2018-8491": {"https://www.jpcert.or.jp/at/2018/at180041.html"},
|
||||
"CVE-2018-8494": {"https://www.jpcert.or.jp/at/2018/at180041.html"},
|
||||
"CVE-2018-8505": {"https://www.jpcert.or.jp/at/2018/at180041.html"},
|
||||
"CVE-2018-8509": {"https://www.jpcert.or.jp/at/2018/at180041.html"},
|
||||
"CVE-2018-8510": {"https://www.jpcert.or.jp/at/2018/at180041.html"},
|
||||
"CVE-2018-8511": {"https://www.jpcert.or.jp/at/2018/at180041.html"},
|
||||
"CVE-2018-8513": {"https://www.jpcert.or.jp/at/2018/at180041.html"},
|
||||
"CVE-2018-8541": {"https://www.jpcert.or.jp/at/2018/at180046.html"},
|
||||
"CVE-2018-8542": {"https://www.jpcert.or.jp/at/2018/at180046.html"},
|
||||
"CVE-2018-8543": {"https://www.jpcert.or.jp/at/2018/at180046.html"},
|
||||
"CVE-2018-8544": {"https://www.jpcert.or.jp/at/2018/at180046.html"},
|
||||
"CVE-2018-8551": {"https://www.jpcert.or.jp/at/2018/at180046.html"},
|
||||
"CVE-2018-8553": {"https://www.jpcert.or.jp/at/2018/at180046.html"},
|
||||
"CVE-2018-8555": {"https://www.jpcert.or.jp/at/2018/at180046.html"},
|
||||
"CVE-2018-8556": {"https://www.jpcert.or.jp/at/2018/at180046.html"},
|
||||
"CVE-2018-8557": {"https://www.jpcert.or.jp/at/2018/at180046.html"},
|
||||
"CVE-2018-8588": {"https://www.jpcert.or.jp/at/2018/at180046.html"},
|
||||
"CVE-2018-8589": {"https://www.jpcert.or.jp/at/2018/at180046.html"},
|
||||
"CVE-2018-8609": {"https://www.jpcert.or.jp/at/2018/at180046.html"},
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package alert
|
||||
|
||||
// CveDictEn has CVE-ID key which included USCERT alerts
|
||||
var CveDictEn = map[string][]string{
|
||||
"CVE-1999-0532": {"https://www.us-cert.gov/ncas/alerts/TA15-103A"},
|
||||
"CVE-2006-3227": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2008-0015": {"https://www.us-cert.gov/ncas/alerts/TA09-195A", "https://www.us-cert.gov/ncas/alerts/TA09-209A"},
|
||||
"CVE-2008-2244": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2009-0658": {"https://www.us-cert.gov/ncas/alerts/TA09-051A"},
|
||||
"CVE-2009-0927": {"https://www.us-cert.gov/ncas/alerts/TA13-141A"},
|
||||
"CVE-2009-1492": {"https://www.us-cert.gov/ncas/alerts/TA09-133B"},
|
||||
"CVE-2009-1493": {"https://www.us-cert.gov/ncas/alerts/TA09-133B"},
|
||||
"CVE-2009-1537": {"https://www.us-cert.gov/ncas/alerts/TA09-195A"},
|
||||
"CVE-2009-3103": {"https://www.us-cert.gov/ncas/alerts/TA17-181A"},
|
||||
"CVE-2009-3129": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2009-3674": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2009-3953": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2010-0018": {"https://www.us-cert.gov/ncas/alerts/TA10-012B"},
|
||||
"CVE-2010-0188": {"https://www.us-cert.gov/ncas/alerts/TA13-141A", "https://www.us-cert.gov/ncas/alerts/TA14-300A", "https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2010-0806": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2010-1297": {"https://www.us-cert.gov/ncas/alerts/TA10-162A", "https://www.us-cert.gov/ncas/alerts/TA10-159A"},
|
||||
"CVE-2010-2883": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2010-3333": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2011-0101": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2011-0611": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2011-2462": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2012-0158": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2012-1723": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2012-1856": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2012-1889": {"https://www.us-cert.gov/ncas/alerts/TA12-174A"},
|
||||
"CVE-2012-3174": {"https://www.us-cert.gov/ncas/alerts/TA13-010A"},
|
||||
"CVE-2012-4681": {"https://www.us-cert.gov/ncas/alerts/TA12-240A"},
|
||||
"CVE-2012-4792": {"https://www.us-cert.gov/ncas/alerts/TA13-015A", "https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2013-0074": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2013-0140": {"https://www.us-cert.gov/ncas/alerts/TA13-193A"},
|
||||
"CVE-2013-0141": {"https://www.us-cert.gov/ncas/alerts/TA13-193A"},
|
||||
"CVE-2013-0422": {"https://www.us-cert.gov/ncas/alerts/TA13-141A", "https://www.us-cert.gov/ncas/alerts/TA13-010A"},
|
||||
"CVE-2013-0625": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2013-0632": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2013-0809": {"https://www.us-cert.gov/ncas/alerts/TA13-064A"},
|
||||
"CVE-2013-1347": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2013-1493": {"https://www.us-cert.gov/ncas/alerts/TA13-064A"},
|
||||
"CVE-2013-1571": {"https://www.us-cert.gov/ncas/alerts/TA13-169A"},
|
||||
"CVE-2013-2465": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2013-2729": {"https://www.us-cert.gov/ncas/alerts/TA14-300A", "https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2013-3336": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2013-5211": {"https://www.us-cert.gov/ncas/alerts/TA14-017A", "https://www.us-cert.gov/ncas/alerts/TA14-013A"},
|
||||
"CVE-2013-5326": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2014-0160": {"https://www.us-cert.gov/ncas/alerts/TA14-098A", "https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2014-0322": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2014-0564": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2014-1761": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2014-1776": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2014-3393": {"https://www.us-cert.gov/ncas/alerts/TA16-250A"},
|
||||
"CVE-2014-3566": {"https://www.us-cert.gov/ncas/alerts/TA14-290A", "https://www.us-cert.gov/ncas/alerts/TA15-120A"},
|
||||
"CVE-2014-4114": {"https://www.us-cert.gov/ncas/alerts/TA15-119A"},
|
||||
"CVE-2014-6271": {"https://www.us-cert.gov/ncas/alerts/TA14-268A"},
|
||||
"CVE-2014-6277": {"https://www.us-cert.gov/ncas/alerts/TA14-268A"},
|
||||
"CVE-2014-6278": {"https://www.us-cert.gov/ncas/alerts/TA14-268A"},
|
||||
"CVE-2014-6321": {"https://www.us-cert.gov/ncas/alerts/TA14-318A"},
|
||||
"CVE-2014-6332": {"https://www.us-cert.gov/ncas/alerts/TA14-318B"},
|
||||
"CVE-2014-7169": {"https://www.us-cert.gov/ncas/alerts/TA14-268A"},
|
||||
"CVE-2014-7186": {"https://www.us-cert.gov/ncas/alerts/TA14-268A"},
|
||||
"CVE-2014-7187": {"https://www.us-cert.gov/ncas/alerts/TA14-268A"},
|
||||
"CVE-2014-8730": {"https://www.us-cert.gov/ncas/alerts/TA14-290A"},
|
||||
"CVE-2015-2387": {"https://www.us-cert.gov/ncas/alerts/TA15-195A"},
|
||||
"CVE-2015-5119": {"https://www.us-cert.gov/ncas/alerts/TA15-195A", "https://www.us-cert.gov/ncas/alerts/TA15-213A"},
|
||||
"CVE-2015-5122": {"https://www.us-cert.gov/ncas/alerts/TA15-195A"},
|
||||
"CVE-2015-5123": {"https://www.us-cert.gov/ncas/alerts/TA15-195A"},
|
||||
"CVE-2015-6585": {"https://www.us-cert.gov/ncas/alerts/TA17-164A"},
|
||||
"CVE-2015-8651": {"https://www.us-cert.gov/ncas/alerts/TA17-164A"},
|
||||
"CVE-2016-0034": {"https://www.us-cert.gov/ncas/alerts/TA17-164A"},
|
||||
"CVE-2016-1019": {"https://www.us-cert.gov/ncas/alerts/TA17-164A"},
|
||||
"CVE-2016-2207": {"https://www.us-cert.gov/ncas/alerts/TA16-187A"},
|
||||
"CVE-2016-2208": {"https://www.us-cert.gov/ncas/alerts/TA16-187A"},
|
||||
"CVE-2016-2209": {"https://www.us-cert.gov/ncas/alerts/TA16-187A"},
|
||||
"CVE-2016-2210": {"https://www.us-cert.gov/ncas/alerts/TA16-187A"},
|
||||
"CVE-2016-2211": {"https://www.us-cert.gov/ncas/alerts/TA16-187A"},
|
||||
"CVE-2016-3644": {"https://www.us-cert.gov/ncas/alerts/TA16-187A"},
|
||||
"CVE-2016-3645": {"https://www.us-cert.gov/ncas/alerts/TA16-187A"},
|
||||
"CVE-2016-4117": {"https://www.us-cert.gov/ncas/alerts/TA17-164A"},
|
||||
"CVE-2016-6366": {"https://www.us-cert.gov/ncas/alerts/TA16-250A"},
|
||||
"CVE-2016-6367": {"https://www.us-cert.gov/ncas/alerts/TA16-250A"},
|
||||
"CVE-2016-6415": {"https://www.us-cert.gov/ncas/alerts/TA16-250A"},
|
||||
"CVE-2016-6909": {"https://www.us-cert.gov/ncas/alerts/TA16-250A"},
|
||||
"CVE-2016-7089": {"https://www.us-cert.gov/ncas/alerts/TA16-250A"},
|
||||
"CVE-2017-0144": {"https://www.us-cert.gov/ncas/alerts/TA17-181A"},
|
||||
"CVE-2017-0145": {"https://www.us-cert.gov/ncas/alerts/TA17-181A"},
|
||||
"CVE-2017-3066": {"https://www.us-cert.gov/ncas/alerts/AA18-284A"},
|
||||
"CVE-2017-5715": {"https://www.us-cert.gov/ncas/alerts/TA18-141A", "https://www.us-cert.gov/ncas/alerts/TA18-004A"},
|
||||
"CVE-2017-5753": {"https://www.us-cert.gov/ncas/alerts/TA18-141A", "https://www.us-cert.gov/ncas/alerts/TA18-004A"},
|
||||
"CVE-2017-5754": {"https://www.us-cert.gov/ncas/alerts/TA18-141A", "https://www.us-cert.gov/ncas/alerts/TA18-004A"},
|
||||
"CVE-2018-1038": {"https://www.us-cert.gov/ncas/alerts/TA18-004A"},
|
||||
"CVE-2018-3639": {"https://www.us-cert.gov/ncas/alerts/TA18-141A"},
|
||||
"CVE-2018-3640": {"https://www.us-cert.gov/ncas/alerts/TA18-141A"},
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package alert
|
||||
|
||||
// GenerateAlertDict returns XCERT alert slice by cveID
|
||||
func GenerateAlertDict(cveID string, lang string) (alerts []Alert) {
|
||||
if lang == "ja" {
|
||||
if keys, ok := CveDictJa[cveID]; ok {
|
||||
for _, key := range keys {
|
||||
alerts = append(alerts, AlertDictJa[key])
|
||||
}
|
||||
}
|
||||
return alerts
|
||||
}
|
||||
|
||||
// default language is English
|
||||
if keys, ok := CveDictEn[cveID]; ok {
|
||||
for _, key := range keys {
|
||||
alerts = append(alerts, AlertDictEn[key])
|
||||
}
|
||||
}
|
||||
return alerts
|
||||
}
|
||||
43
cache/bolt.go
vendored
43
cache/bolt.go
vendored
@@ -1,42 +1,25 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"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
|
||||
Log logging.Logger
|
||||
db *bolt.DB
|
||||
}
|
||||
|
||||
// SetupBolt opens a boltdb and creates a meta bucket if not exists.
|
||||
func SetupBolt(path string, l *logrus.Entry) error {
|
||||
func SetupBolt(path string, l logging.Logger) error {
|
||||
l.Infof("Open boltDB: %s", path)
|
||||
db, err := bolt.Open(path, 0600, nil)
|
||||
if err != nil {
|
||||
@@ -64,12 +47,12 @@ func (b Bolt) Close() error {
|
||||
return b.db.Close()
|
||||
}
|
||||
|
||||
// CreateBucketIfNotExists creates a buket that is specified by arg.
|
||||
// CreateBucketIfNotExists creates a bucket 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 fmt.Errorf("Failed to create bucket: %s", err)
|
||||
return xerrors.Errorf("Failed to create bucket: %w", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -98,7 +81,7 @@ func (b Bolt) RefreshMeta(meta Meta) error {
|
||||
meta.CreatedAt = time.Now()
|
||||
jsonBytes, err := json.Marshal(meta)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to marshal to JSON: %s", err)
|
||||
return xerrors.Errorf("Failed to marshal to JSON: %w", err)
|
||||
}
|
||||
return b.db.Update(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket([]byte(metabucket))
|
||||
@@ -110,11 +93,11 @@ func (b Bolt) RefreshMeta(meta Meta) error {
|
||||
})
|
||||
}
|
||||
|
||||
// EnsureBuckets puts a Meta information and create a buket that holds changelogs.
|
||||
// EnsureBuckets puts a Meta information and create a bucket that holds changelogs.
|
||||
func (b Bolt) EnsureBuckets(meta Meta) error {
|
||||
jsonBytes, err := json.Marshal(meta)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to marshal to JSON: %s", err)
|
||||
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)
|
||||
@@ -158,12 +141,12 @@ func (b Bolt) PrettyPrint(meta Meta) error {
|
||||
})
|
||||
}
|
||||
|
||||
// GetChangelog get the changelgo of specified packName from the Bucket
|
||||
// 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 fmt.Errorf("Failed to get Bucket: %s", servername)
|
||||
return xerrors.Errorf("Failed to get Bucket: %s", servername)
|
||||
}
|
||||
v := bkt.Get([]byte(packName))
|
||||
if v == nil {
|
||||
@@ -176,12 +159,12 @@ func (b Bolt) GetChangelog(servername, packName string) (changelog string, err e
|
||||
return
|
||||
}
|
||||
|
||||
// PutChangelog put the changelgo of specified packName into the Bucket
|
||||
// PutChangelog put the changelog 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 fmt.Errorf("Failed to get Bucket: %s", servername)
|
||||
return xerrors.Errorf("Failed to get Bucket: %s", servername)
|
||||
}
|
||||
return bkt.Put([]byte(packName), []byte(changelog))
|
||||
})
|
||||
|
||||
29
cache/bolt_test.go
vendored
29
cache/bolt_test.go
vendored
@@ -1,20 +1,3 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
@@ -24,8 +7,8 @@ import (
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const path = "/tmp/vuls-test-cache-11111111.db"
|
||||
@@ -46,7 +29,7 @@ var meta = Meta{
|
||||
}
|
||||
|
||||
func TestSetupBolt(t *testing.T) {
|
||||
log := logrus.NewEntry(&logrus.Logger{})
|
||||
log := logging.NewNormalLogger()
|
||||
err := SetupBolt(path, log)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to setup bolt: %s", err)
|
||||
@@ -63,7 +46,7 @@ func TestSetupBolt(t *testing.T) {
|
||||
t.Errorf("Failed to open bolt: %s", err)
|
||||
}
|
||||
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
_ = db.View(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket([]byte(metabucket))
|
||||
if bkt == nil {
|
||||
t.Errorf("Meta bucket nof found")
|
||||
@@ -74,7 +57,7 @@ func TestSetupBolt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEnsureBuckets(t *testing.T) {
|
||||
log := logrus.NewEntry(&logrus.Logger{})
|
||||
log := logging.NewNormalLogger()
|
||||
if err := SetupBolt(path, log); err != nil {
|
||||
t.Errorf("Failed to setup bolt: %s", err)
|
||||
}
|
||||
@@ -104,7 +87,7 @@ func TestEnsureBuckets(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("Failed to open bolt: %s", err)
|
||||
}
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
_ = db.View(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket([]byte(servername))
|
||||
if bkt == nil {
|
||||
t.Errorf("Meta bucket nof found")
|
||||
@@ -115,7 +98,7 @@ func TestEnsureBuckets(t *testing.T) {
|
||||
|
||||
func TestPutGetChangelog(t *testing.T) {
|
||||
clog := "changelog-text"
|
||||
log := logrus.NewEntry(&logrus.Logger{})
|
||||
log := logging.NewNormalLogger()
|
||||
if err := SetupBolt(path, log); err != nil {
|
||||
t.Errorf("Failed to setup bolt: %s", err)
|
||||
}
|
||||
|
||||
17
cache/db.go
vendored
17
cache/db.go
vendored
@@ -1,20 +1,3 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
|
||||
36
cmd/scanner/main.go
Normal file
36
cmd/scanner/main.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"context"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
commands "github.com/future-architect/vuls/subcmds"
|
||||
"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.ScanCmd{}, "scan")
|
||||
subcommands.Register(&commands.HistoryCmd{}, "history")
|
||||
subcommands.Register(&commands.ConfigtestCmd{}, "configtest")
|
||||
subcommands.Register(&commands.SaaSCmd{}, "saas")
|
||||
|
||||
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)))
|
||||
}
|
||||
@@ -1,20 +1,3 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -24,8 +7,8 @@ import (
|
||||
|
||||
"context"
|
||||
|
||||
"github.com/future-architect/vuls/commands"
|
||||
"github.com/future-architect/vuls/config"
|
||||
commands "github.com/future-architect/vuls/subcmds"
|
||||
"github.com/google/subcommands"
|
||||
)
|
||||
|
||||
@@ -46,7 +29,7 @@ func main() {
|
||||
flag.Parse()
|
||||
|
||||
if *v {
|
||||
fmt.Printf("vuls %s %s\n", config.Version, config.Revision)
|
||||
fmt.Printf("vuls-%s-%s\n", config.Version, config.Revision)
|
||||
os.Exit(int(subcommands.ExitSuccess))
|
||||
}
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"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-external]
|
||||
[-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,
|
||||
"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 {
|
||||
// Setup Logger
|
||||
util.Log = util.NewCustomLogger(c.ServerInfo{})
|
||||
|
||||
if err := mkdirDotVuls(); err != nil {
|
||||
util.Log.Errorf("Failed to create .vuls: %s", 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 {
|
||||
util.Log.Errorf("Error loading %s, %s", p.configPath, err)
|
||||
util.Log.Errorf("If you update Vuls and get this error, there may be incompatible changes in config.toml")
|
||||
util.Log.Errorf("Please check README: https://github.com/future-architect/vuls#configuration")
|
||||
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: %s", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
|
||||
util.Log.Info("Checking Scan Modes...")
|
||||
if err := scan.CheckScanModes(); err != nil {
|
||||
util.Log.Errorf("Fix config.toml: %s", 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
|
||||
}
|
||||
@@ -1,428 +0,0 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
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/oval"
|
||||
"github.com/future-architect/vuls/report"
|
||||
"github.com/future-architect/vuls/util"
|
||||
"github.com/google/subcommands"
|
||||
"github.com/k0kubun/pp"
|
||||
cvelog "github.com/kotakanbe/go-cve-dictionary/log"
|
||||
)
|
||||
|
||||
// ReportCmd is subcommand for reporting
|
||||
type ReportCmd struct {
|
||||
configPath string
|
||||
cveDict c.GoCveDictConf
|
||||
ovalDict c.GovalDictConf
|
||||
gostConf c.GostConf
|
||||
exploitConf c.ExploitConf
|
||||
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]
|
||||
[-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]
|
||||
[-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]
|
||||
[-http="http://vuls-report-server"]
|
||||
|
||||
[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")
|
||||
|
||||
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.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.httpConf.URL, "http", "", "-to-http http://vuls-report")
|
||||
|
||||
}
|
||||
|
||||
// Execute execute
|
||||
func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
||||
util.Log = util.NewCustomLogger(c.ServerInfo{})
|
||||
cvelog.SetLogger(c.Conf.LogDir, false, c.Conf.Debug, false)
|
||||
|
||||
if err := c.Load(p.configPath, ""); err != nil {
|
||||
util.Log.Errorf("Error loading %s, %s", 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.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: %s", 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: %s",
|
||||
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: %s",
|
||||
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
|
||||
for _, r := range loaded {
|
||||
if len(r.Errors) == 0 {
|
||||
res = append(res, r)
|
||||
} else {
|
||||
util.Log.Warnf("Ignored since errors occurred during scanning: %s",
|
||||
r.ServerName)
|
||||
}
|
||||
}
|
||||
|
||||
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: %s", 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: %s", 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: %s", 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: %s", err)
|
||||
util.Log.Errorf("Run go-exploitdb 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,
|
||||
DebugSQL: c.Conf.DebugSQL,
|
||||
})
|
||||
if locked {
|
||||
util.Log.Errorf("SQLite3 is locked. Close other DB connections and try again: %s", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
if err != nil {
|
||||
util.Log.Errorf("Failed to init DB Clients: %s", 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 _, w := range reports {
|
||||
if err := w.Write(res...); err != nil {
|
||||
util.Log.Errorf("Failed to report: %s", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
}
|
||||
|
||||
return subcommands.ExitSuccess
|
||||
}
|
||||
219
commands/scan.go
219
commands/scan.go
@@ -1,219 +0,0 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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]
|
||||
[-skip-broken]
|
||||
[-http-proxy=http://192.168.0.1:8080]
|
||||
[-ask-key-password]
|
||||
[-timeout=300]
|
||||
[-timeout-scan=7200]
|
||||
[-debug]
|
||||
[-pipe]
|
||||
[-vvv]
|
||||
|
||||
[SERVER]...
|
||||
`
|
||||
}
|
||||
|
||||
// SetFlags set flag
|
||||
func (p *ScanCmd) SetFlags(f *flag.FlagSet) {
|
||||
f.BoolVar(&c.Conf.Debug, "debug", false, "debug mode")
|
||||
|
||||
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,
|
||||
"Use SSH options specified in ssh_config preferentially")
|
||||
|
||||
f.BoolVar(&c.Conf.ContainersOnly, "containers-only", false,
|
||||
"Scan containers only. Default: Scan both of hosts and containers")
|
||||
|
||||
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.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: %s", 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 {
|
||||
util.Log.Errorf("Error loading %s, %s", p.configPath, err)
|
||||
util.Log.Errorf("If you update Vuls and get this error, there may be incompatible changes in config.toml")
|
||||
util.Log.Errorf("Please check README: https://github.com/future-architect/vuls#configuration")
|
||||
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: %s", 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: %s", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
|
||||
util.Log.Info("Checking Scan Modes... ")
|
||||
if err := scan.CheckScanModes(); err != nil {
|
||||
util.Log.Errorf("Fix config.toml: %s", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
|
||||
util.Log.Info("Detecting Platforms... ")
|
||||
scan.DetectPlatforms(p.timeoutSec)
|
||||
|
||||
util.Log.Info("Scanning vulnerabilities... ")
|
||||
if err := scan.Scan(p.scanTimeoutSec); err != nil {
|
||||
util.Log.Errorf("Failed to scan. err: %s", 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
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Architect, Inc. Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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/oval"
|
||||
"github.com/future-architect/vuls/report"
|
||||
"github.com/future-architect/vuls/server"
|
||||
"github.com/future-architect/vuls/util"
|
||||
"github.com/google/subcommands"
|
||||
cvelog "github.com/kotakanbe/go-cve-dictionary/log"
|
||||
)
|
||||
|
||||
// ServerCmd is subcommand for server
|
||||
type ServerCmd struct {
|
||||
configPath string
|
||||
listen string
|
||||
cveDict c.GoCveDictConf
|
||||
ovalDict c.GovalDictConf
|
||||
gostConf c.GostConf
|
||||
exploitConf c.ExploitConf
|
||||
}
|
||||
|
||||
// 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]
|
||||
|
||||
[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()
|
||||
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.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")
|
||||
}
|
||||
|
||||
// Execute execute
|
||||
func (p *ServerCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
||||
util.Log = util.NewCustomLogger(c.ServerInfo{})
|
||||
cvelog.SetLogger(c.Conf.LogDir, false, c.Conf.Debug, false)
|
||||
|
||||
if err := c.Load(p.configPath, ""); err != nil {
|
||||
util.Log.Errorf("Error loading %s, %s", 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)
|
||||
|
||||
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: %s", 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: %s", 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: %s", err)
|
||||
util.Log.Errorf("Run go-exploitdb 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,
|
||||
DebugSQL: c.Conf.DebugSQL,
|
||||
})
|
||||
if locked {
|
||||
util.Log.Errorf("SQLite3 is locked. Close other DB connections and try again: %s", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
util.Log.Errorf("Failed to init DB Clients: %s", 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: %s", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
return subcommands.ExitSuccess
|
||||
}
|
||||
249
commands/tui.go
249
commands/tui.go
@@ -1,249 +0,0 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
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/oval"
|
||||
"github.com/future-architect/vuls/report"
|
||||
"github.com/future-architect/vuls/util"
|
||||
"github.com/google/subcommands"
|
||||
cvelog "github.com/kotakanbe/go-cve-dictionary/log"
|
||||
)
|
||||
|
||||
// TuiCmd is Subcommand of host discovery mode
|
||||
type TuiCmd struct {
|
||||
configPath string
|
||||
cveDict c.GoCveDictConf
|
||||
ovalDict c.GovalDictConf
|
||||
gostConf c.GostConf
|
||||
exploitConf c.ExploitConf
|
||||
}
|
||||
|
||||
// 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]
|
||||
[-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]
|
||||
|
||||
`
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
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")
|
||||
|
||||
}
|
||||
|
||||
// Execute execute
|
||||
func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
||||
c.Conf.Lang = "en"
|
||||
|
||||
// Setup Logger
|
||||
util.Log = util.NewCustomLogger(c.ServerInfo{})
|
||||
cvelog.SetLogger(c.Conf.LogDir, false, c.Conf.Debug, false)
|
||||
|
||||
if err := c.Load(p.configPath, ""); err != nil {
|
||||
util.Log.Errorf("Error loading %s, %s", 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)
|
||||
|
||||
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: %s", 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: %s", 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: %s", 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: %s", err)
|
||||
util.Log.Errorf("Run go-exploitdb 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,
|
||||
DebugSQL: c.Conf.DebugSQL,
|
||||
})
|
||||
if locked {
|
||||
util.Log.Errorf("SQLite3 is locked. Close other DB connections and try again: %s", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
util.Log.Errorf("Failed to init DB Clients: %s", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
|
||||
defer dbclient.CloseDB()
|
||||
|
||||
if res, err = report.FillCveInfos(*dbclient, res, dir); err != nil {
|
||||
util.Log.Error(err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
return report.RunTui(res)
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/howeyc/gopass"
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
)
|
||||
|
||||
func getPasswd(prompt string) (string, error) {
|
||||
for {
|
||||
fmt.Print(prompt)
|
||||
pass, err := gopass.GetPasswdMasked()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Failed to read 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
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package commands
|
||||
30
config/awsconf.go
Normal file
30
config/awsconf.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package config
|
||||
|
||||
// AWSConf is aws config
|
||||
type AWSConf struct {
|
||||
// AWS profile to use
|
||||
Profile string `json:"profile"`
|
||||
|
||||
// AWS region to use
|
||||
Region string `json:"region"`
|
||||
|
||||
// S3 bucket name
|
||||
S3Bucket string `json:"s3Bucket"`
|
||||
|
||||
// /bucket/path/to/results
|
||||
S3ResultsDir string `json:"s3ResultsDir"`
|
||||
|
||||
// The Server-side encryption algorithm used when storing the reports in S3 (e.g., AES256, aws:kms).
|
||||
S3ServerSideEncryption string `json:"s3ServerSideEncryption"`
|
||||
|
||||
Enabled bool `toml:"-" json:"-"`
|
||||
}
|
||||
|
||||
// Validate configuration
|
||||
func (c *AWSConf) Validate() (errs []error) {
|
||||
// TODO
|
||||
if !c.Enabled {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
46
config/azureconf.go
Normal file
46
config/azureconf.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// AzureConf is azure config
|
||||
type AzureConf struct {
|
||||
// Azure account name to use. AZURE_STORAGE_ACCOUNT environment variable is used if not specified
|
||||
AccountName string `json:"accountName"`
|
||||
|
||||
// Azure account key to use. AZURE_STORAGE_ACCESS_KEY environment variable is used if not specified
|
||||
AccountKey string `json:"-"`
|
||||
|
||||
// Azure storage container name
|
||||
ContainerName string `json:"containerName"`
|
||||
|
||||
Enabled bool `toml:"-" json:"-"`
|
||||
}
|
||||
|
||||
const (
|
||||
azureAccount = "AZURE_STORAGE_ACCOUNT"
|
||||
azureKey = "AZURE_STORAGE_ACCESS_KEY"
|
||||
)
|
||||
|
||||
// Validate configuration
|
||||
func (c *AzureConf) Validate() (errs []error) {
|
||||
if !c.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
// overwrite if env var is not empty
|
||||
if os.Getenv(azureAccount) != "" {
|
||||
c.AccountName = os.Getenv(azureAccount)
|
||||
}
|
||||
if os.Getenv(azureKey) != "" {
|
||||
c.AccountKey = os.Getenv(azureKey)
|
||||
}
|
||||
|
||||
if c.ContainerName == "" {
|
||||
errs = append(errs, xerrors.Errorf("Azure storage container name is required"))
|
||||
}
|
||||
return
|
||||
}
|
||||
33
config/chatworkconf.go
Normal file
33
config/chatworkconf.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/asaskevich/govalidator"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// ChatWorkConf is ChatWork config
|
||||
type ChatWorkConf struct {
|
||||
APIToken string `json:"-"`
|
||||
Room string `json:"-"`
|
||||
Enabled bool `toml:"-" json:"-"`
|
||||
}
|
||||
|
||||
// Validate validates configuration
|
||||
func (c *ChatWorkConf) Validate() (errs []error) {
|
||||
if !c.Enabled {
|
||||
return
|
||||
}
|
||||
if len(c.Room) == 0 {
|
||||
errs = append(errs, xerrors.New("chatWorkConf.room must not be empty"))
|
||||
}
|
||||
|
||||
if len(c.APIToken) == 0 {
|
||||
errs = append(errs, xerrors.New("chatWorkConf.ApiToken must not be empty"))
|
||||
}
|
||||
|
||||
_, err := govalidator.ValidateStruct(c)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,20 +1,3 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
var (
|
||||
|
||||
1260
config/config.go
1260
config/config.go
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,8 @@ package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/future-architect/vuls/constant"
|
||||
)
|
||||
|
||||
func TestSyslogConfValidate(t *testing.T) {
|
||||
@@ -55,7 +57,7 @@ func TestSyslogConfValidate(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
Conf.ToSyslog = true
|
||||
tt.conf.Enabled = true
|
||||
errs := tt.conf.Validate()
|
||||
if len(errs) != tt.expectedErrLength {
|
||||
t.Errorf("test: %d, expected %d, actual %d", i, tt.expectedErrLength, len(errs))
|
||||
@@ -63,7 +65,7 @@ func TestSyslogConfValidate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMajorVersion(t *testing.T) {
|
||||
func TestDistro_MajorVersion(t *testing.T) {
|
||||
var tests = []struct {
|
||||
in Distro
|
||||
out int
|
||||
|
||||
32
config/googlechatconf.go
Normal file
32
config/googlechatconf.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/asaskevich/govalidator"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// GoogleChatConf is GoogleChat config
|
||||
type GoogleChatConf struct {
|
||||
WebHookURL string `valid:"url" json:"-" toml:"webHookURL,omitempty"`
|
||||
SkipIfNoCve bool `valid:"type(bool)" json:"-" toml:"skipIfNoCve"`
|
||||
ServerNameRegexp string `valid:"type(string)" json:"-" toml:"serverNameRegexp,omitempty"`
|
||||
Enabled bool `valid:"type(bool)" json:"-" toml:"-"`
|
||||
}
|
||||
|
||||
// Validate validates configuration
|
||||
func (c *GoogleChatConf) Validate() (errs []error) {
|
||||
if !c.Enabled {
|
||||
return
|
||||
}
|
||||
if len(c.WebHookURL) == 0 {
|
||||
errs = append(errs, xerrors.New("googleChatConf.webHookURL must not be empty"))
|
||||
}
|
||||
if !govalidator.IsRegex(c.ServerNameRegexp) {
|
||||
errs = append(errs, xerrors.New("googleChatConf.serverNameRegexp must be regex"))
|
||||
}
|
||||
_, err := govalidator.ValidateStruct(c)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
32
config/httpconf.go
Normal file
32
config/httpconf.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
)
|
||||
|
||||
// HTTPConf is HTTP config
|
||||
type HTTPConf struct {
|
||||
URL string `valid:"url" json:"-"`
|
||||
Enabled bool `toml:"-" json:"-"`
|
||||
}
|
||||
|
||||
const httpKey = "VULS_HTTP_URL"
|
||||
|
||||
// Validate validates configuration
|
||||
func (c *HTTPConf) Validate() (errs []error) {
|
||||
if !c.Enabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
// overwrite if env var is not empty
|
||||
if os.Getenv(httpKey) != "" {
|
||||
c.URL = os.Getenv(httpKey)
|
||||
}
|
||||
|
||||
if _, err := govalidator.ValidateStruct(c); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return errs
|
||||
}
|
||||
@@ -1,29 +1,12 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import "fmt"
|
||||
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 fmt.Errorf("Not implement yet")
|
||||
func (c JSONLoader) Load(_, _, _ string) (err error) {
|
||||
return xerrors.New("Not implement yet")
|
||||
}
|
||||
|
||||
@@ -1,20 +1,3 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
// Load loads configuration
|
||||
|
||||
211
config/os.go
Normal file
211
config/os.go
Normal file
@@ -0,0 +1,211 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/future-architect/vuls/constant"
|
||||
)
|
||||
|
||||
// EOL has End-of-Life information
|
||||
type EOL struct {
|
||||
StandardSupportUntil time.Time
|
||||
ExtendedSupportUntil time.Time
|
||||
Ended bool
|
||||
}
|
||||
|
||||
// IsStandardSupportEnded checks now is under standard support
|
||||
func (e EOL) IsStandardSupportEnded(now time.Time) bool {
|
||||
return e.Ended ||
|
||||
!e.ExtendedSupportUntil.IsZero() && e.StandardSupportUntil.IsZero() ||
|
||||
!e.StandardSupportUntil.IsZero() && now.After(e.StandardSupportUntil)
|
||||
}
|
||||
|
||||
// IsExtendedSuppportEnded checks now is under extended support
|
||||
func (e EOL) IsExtendedSuppportEnded(now time.Time) bool {
|
||||
if e.Ended {
|
||||
return true
|
||||
}
|
||||
if e.StandardSupportUntil.IsZero() && e.ExtendedSupportUntil.IsZero() {
|
||||
return false
|
||||
}
|
||||
return !e.ExtendedSupportUntil.IsZero() && now.After(e.ExtendedSupportUntil) ||
|
||||
e.ExtendedSupportUntil.IsZero() && now.After(e.StandardSupportUntil)
|
||||
}
|
||||
|
||||
// GetEOL return EOL information for the OS-release passed by args
|
||||
// https://github.com/aquasecurity/trivy/blob/master/pkg/detector/ospkg/redhat/redhat.go#L20
|
||||
func GetEOL(family, release string) (eol EOL, found bool) {
|
||||
switch family {
|
||||
case constant.Amazon:
|
||||
rel := "2"
|
||||
if isAmazonLinux1(release) {
|
||||
rel = "1"
|
||||
}
|
||||
eol, found = map[string]EOL{
|
||||
"1": {StandardSupportUntil: time.Date(2023, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
"2": {},
|
||||
}[rel]
|
||||
case constant.RedHat:
|
||||
// https://access.redhat.com/support/policy/updates/errata
|
||||
eol, found = map[string]EOL{
|
||||
"3": {Ended: true},
|
||||
"4": {Ended: true},
|
||||
"5": {Ended: true},
|
||||
"6": {
|
||||
StandardSupportUntil: time.Date(2020, 11, 30, 23, 59, 59, 0, time.UTC),
|
||||
ExtendedSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC),
|
||||
},
|
||||
"7": {
|
||||
StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC),
|
||||
},
|
||||
"8": {
|
||||
StandardSupportUntil: time.Date(2029, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
},
|
||||
}[major(release)]
|
||||
case constant.CentOS:
|
||||
// https://en.wikipedia.org/wiki/CentOS#End-of-support_schedule
|
||||
// TODO Stream
|
||||
eol, found = map[string]EOL{
|
||||
"3": {Ended: true},
|
||||
"4": {Ended: true},
|
||||
"5": {Ended: true},
|
||||
"6": {Ended: true},
|
||||
"7": {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
"8": {StandardSupportUntil: time.Date(2021, 12, 31, 23, 59, 59, 0, time.UTC)},
|
||||
}[major(release)]
|
||||
case constant.Alma:
|
||||
eol, found = map[string]EOL{
|
||||
"8": {StandardSupportUntil: time.Date(2029, 12, 31, 23, 59, 59, 0, time.UTC)},
|
||||
}[major(release)]
|
||||
case constant.Rocky:
|
||||
eol, found = map[string]EOL{
|
||||
"8": {StandardSupportUntil: time.Date(2029, 5, 31, 23, 59, 59, 0, time.UTC)},
|
||||
}[major(release)]
|
||||
case constant.Oracle:
|
||||
eol, found = map[string]EOL{
|
||||
// Source:
|
||||
// https://www.oracle.com/a/ocom/docs/elsp-lifetime-069338.pdf
|
||||
// https://community.oracle.com/docs/DOC-917964
|
||||
"3": {Ended: true},
|
||||
"4": {Ended: true},
|
||||
"5": {Ended: true},
|
||||
"6": {
|
||||
StandardSupportUntil: time.Date(2021, 3, 1, 23, 59, 59, 0, time.UTC),
|
||||
ExtendedSupportUntil: time.Date(2024, 3, 1, 23, 59, 59, 0, time.UTC),
|
||||
},
|
||||
"7": {
|
||||
StandardSupportUntil: time.Date(2024, 7, 1, 23, 59, 59, 0, time.UTC),
|
||||
},
|
||||
"8": {
|
||||
StandardSupportUntil: time.Date(2029, 7, 1, 23, 59, 59, 0, time.UTC),
|
||||
},
|
||||
}[major(release)]
|
||||
case constant.Debian:
|
||||
eol, found = map[string]EOL{
|
||||
// https://wiki.debian.org/LTS
|
||||
"6": {Ended: true},
|
||||
"7": {Ended: true},
|
||||
"8": {Ended: true},
|
||||
"9": {StandardSupportUntil: time.Date(2022, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
"10": {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
"11": {StandardSupportUntil: time.Date(2026, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
}[major(release)]
|
||||
case constant.Raspbian:
|
||||
// Not found
|
||||
eol, found = map[string]EOL{}[major(release)]
|
||||
case constant.Ubuntu:
|
||||
// https://wiki.ubuntu.com/Releases
|
||||
eol, found = map[string]EOL{
|
||||
"14.10": {Ended: true},
|
||||
"14.04": {
|
||||
ExtendedSupportUntil: time.Date(2022, 4, 1, 23, 59, 59, 0, time.UTC),
|
||||
},
|
||||
"15.04": {Ended: true},
|
||||
"16.10": {Ended: true},
|
||||
"17.04": {Ended: true},
|
||||
"17.10": {Ended: true},
|
||||
"16.04": {
|
||||
StandardSupportUntil: time.Date(2021, 4, 1, 23, 59, 59, 0, time.UTC),
|
||||
ExtendedSupportUntil: time.Date(2024, 4, 1, 23, 59, 59, 0, time.UTC),
|
||||
},
|
||||
"18.04": {
|
||||
StandardSupportUntil: time.Date(2023, 4, 1, 23, 59, 59, 0, time.UTC),
|
||||
ExtendedSupportUntil: time.Date(2028, 4, 1, 23, 59, 59, 0, time.UTC),
|
||||
},
|
||||
"18.10": {Ended: true},
|
||||
"19.04": {Ended: true},
|
||||
"19.10": {Ended: true},
|
||||
"20.04": {
|
||||
StandardSupportUntil: time.Date(2025, 4, 1, 23, 59, 59, 0, time.UTC),
|
||||
},
|
||||
"20.10": {
|
||||
StandardSupportUntil: time.Date(2021, 7, 22, 23, 59, 59, 0, time.UTC),
|
||||
},
|
||||
"21.04": {
|
||||
StandardSupportUntil: time.Date(2022, 1, 22, 23, 59, 59, 0, time.UTC),
|
||||
},
|
||||
"21.10": {
|
||||
StandardSupportUntil: time.Date(2022, 7, 1, 23, 59, 59, 0, time.UTC),
|
||||
},
|
||||
}[release]
|
||||
case constant.SUSEEnterpriseServer:
|
||||
//TODO
|
||||
case constant.Alpine:
|
||||
// https://github.com/aquasecurity/trivy/blob/master/pkg/detector/ospkg/alpine/alpine.go#L19
|
||||
// https://wiki.alpinelinux.org/wiki/Alpine_Linux:Releases
|
||||
eol, found = map[string]EOL{
|
||||
"2.0": {Ended: true},
|
||||
"2.1": {Ended: true},
|
||||
"2.2": {Ended: true},
|
||||
"2.3": {Ended: true},
|
||||
"2.4": {Ended: true},
|
||||
"2.5": {Ended: true},
|
||||
"2.6": {Ended: true},
|
||||
"2.7": {Ended: true},
|
||||
"3.0": {Ended: true},
|
||||
"3.1": {Ended: true},
|
||||
"3.2": {Ended: true},
|
||||
"3.3": {Ended: true},
|
||||
"3.4": {Ended: true},
|
||||
"3.5": {Ended: true},
|
||||
"3.6": {Ended: true},
|
||||
"3.7": {Ended: true},
|
||||
"3.8": {Ended: true},
|
||||
"3.9": {Ended: true},
|
||||
"3.10": {StandardSupportUntil: time.Date(2021, 5, 1, 23, 59, 59, 0, time.UTC)},
|
||||
"3.11": {StandardSupportUntil: time.Date(2021, 11, 1, 23, 59, 59, 0, time.UTC)},
|
||||
"3.12": {StandardSupportUntil: time.Date(2022, 5, 1, 23, 59, 59, 0, time.UTC)},
|
||||
"3.13": {StandardSupportUntil: time.Date(2022, 11, 1, 23, 59, 59, 0, time.UTC)},
|
||||
}[majorDotMinor(release)]
|
||||
case constant.FreeBSD:
|
||||
// https://www.freebsd.org/security/
|
||||
eol, found = map[string]EOL{
|
||||
"7": {Ended: true},
|
||||
"8": {Ended: true},
|
||||
"9": {Ended: true},
|
||||
"10": {Ended: true},
|
||||
"11": {StandardSupportUntil: time.Date(2021, 9, 30, 23, 59, 59, 0, time.UTC)},
|
||||
"12": {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
"13": {StandardSupportUntil: time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)},
|
||||
}[major(release)]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func major(osVer string) (majorVersion string) {
|
||||
return strings.Split(osVer, ".")[0]
|
||||
}
|
||||
|
||||
func majorDotMinor(osVer string) (majorDotMinor string) {
|
||||
ss := strings.SplitN(osVer, ".", 3)
|
||||
if len(ss) == 1 {
|
||||
return osVer
|
||||
}
|
||||
return fmt.Sprintf("%s.%s", ss[0], ss[1])
|
||||
}
|
||||
|
||||
func isAmazonLinux1(osRelease string) bool {
|
||||
return len(strings.Fields(osRelease)) == 1
|
||||
}
|
||||
449
config/os_test.go
Normal file
449
config/os_test.go
Normal file
@@ -0,0 +1,449 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/future-architect/vuls/constant"
|
||||
)
|
||||
|
||||
func TestEOL_IsStandardSupportEnded(t *testing.T) {
|
||||
type fields struct {
|
||||
family string
|
||||
release string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
now time.Time
|
||||
found bool
|
||||
stdEnded bool
|
||||
extEnded bool
|
||||
}{
|
||||
// Amazon Linux
|
||||
{
|
||||
name: "amazon linux 1 supported",
|
||||
fields: fields{family: Amazon, release: "2018.03"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "amazon linux 1 eol on 2023-6-30",
|
||||
fields: fields{family: Amazon, release: "2018.03"},
|
||||
now: time.Date(2023, 7, 1, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: true,
|
||||
extEnded: true,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "amazon linux 2 supported",
|
||||
fields: fields{family: Amazon, release: "2 (Karoo)"},
|
||||
now: time.Date(2023, 7, 1, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
//RHEL
|
||||
{
|
||||
name: "RHEL7 supported",
|
||||
fields: fields{family: RedHat, release: "7"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "RHEL8 supported",
|
||||
fields: fields{family: RedHat, release: "8"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "RHEL6 eol",
|
||||
fields: fields{family: RedHat, release: "6"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: true,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "RHEL9 not found",
|
||||
fields: fields{family: RedHat, release: "9"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: false,
|
||||
},
|
||||
//CentOS
|
||||
{
|
||||
name: "CentOS 7 supported",
|
||||
fields: fields{family: CentOS, release: "7"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "CentOS 8 supported",
|
||||
fields: fields{family: CentOS, release: "8"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "CentOS 6 eol",
|
||||
fields: fields{family: CentOS, release: "6"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: true,
|
||||
extEnded: true,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "CentOS 9 not found",
|
||||
fields: fields{family: CentOS, release: "9"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: false,
|
||||
},
|
||||
// Alma
|
||||
{
|
||||
name: "Alma Linux 8 supported",
|
||||
fields: fields{family: Alma, release: "8"},
|
||||
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Alma Linux 8 EOL",
|
||||
fields: fields{family: Alma, release: "8"},
|
||||
now: time.Date(2029, 2, 1, 0, 0, 0, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Alma Linux 9 Not Found",
|
||||
fields: fields{family: Alma, release: "9"},
|
||||
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: false,
|
||||
},
|
||||
// Rocky
|
||||
{
|
||||
name: "Rocky Linux 8 supported",
|
||||
fields: fields{family: Rocky, release: "8"},
|
||||
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Rocky Linux 8 EOL",
|
||||
fields: fields{family: Rocky, release: "8"},
|
||||
now: time.Date(2026, 2, 1, 0, 0, 0, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Rocky Linux 9 Not Found",
|
||||
fields: fields{family: Rocky, release: "9"},
|
||||
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: false,
|
||||
},
|
||||
//Oracle
|
||||
{
|
||||
name: "Oracle Linux 7 supported",
|
||||
fields: fields{family: Oracle, release: "7"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Oracle Linux 8 supported",
|
||||
fields: fields{family: Oracle, release: "8"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Oracle Linux 6 eol",
|
||||
fields: fields{family: Oracle, release: "6"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Oracle Linux 9 not found",
|
||||
fields: fields{family: Oracle, release: "9"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: false,
|
||||
},
|
||||
//Ubuntu
|
||||
{
|
||||
name: "Ubuntu 18.04 supported",
|
||||
fields: fields{family: Ubuntu, release: "18.04"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Ubuntu 18.04 ext supported",
|
||||
fields: fields{family: Ubuntu, release: "18.04"},
|
||||
now: time.Date(2025, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: true,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Ubuntu 16.04 supported",
|
||||
fields: fields{family: Ubuntu, release: "18.04"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Ubuntu 14.04 eol",
|
||||
fields: fields{family: Ubuntu, release: "14.04"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: true,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Ubuntu 14.10 eol",
|
||||
fields: fields{family: Ubuntu, release: "14.10"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: true,
|
||||
extEnded: true,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Ubuntu 12.10 not found",
|
||||
fields: fields{family: Ubuntu, release: "12.10"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
found: false,
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
},
|
||||
{
|
||||
name: "Ubuntu 20.10 supported",
|
||||
fields: fields{family: Ubuntu, release: "20.10"},
|
||||
now: time.Date(2021, 5, 1, 23, 59, 59, 0, time.UTC),
|
||||
found: true,
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
},
|
||||
{
|
||||
name: "Ubuntu 21.04 supported",
|
||||
fields: fields{family: Ubuntu, release: "21.04"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
found: true,
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
},
|
||||
//Debian
|
||||
{
|
||||
name: "Debian 9 supported",
|
||||
fields: fields{family: Debian, release: "9"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Debian 10 supported",
|
||||
fields: fields{family: Debian, release: "10"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Debian 8 supported",
|
||||
fields: fields{family: Debian, release: "8"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: true,
|
||||
extEnded: true,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Debian 11 supported",
|
||||
fields: fields{family: Debian, release: "11"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Debian 12 is not supported yet",
|
||||
fields: fields{family: Debian, release: "12"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: false,
|
||||
},
|
||||
//alpine
|
||||
{
|
||||
name: "alpine 3.10 supported",
|
||||
fields: fields{family: Alpine, release: "3.10"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Alpine 3.11 supported",
|
||||
fields: fields{family: Alpine, release: "3.11"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Alpine 3.12 supported",
|
||||
fields: fields{family: Alpine, release: "3.12"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Alpine 3.9 eol",
|
||||
fields: fields{family: Alpine, release: "3.9"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: true,
|
||||
extEnded: true,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Alpine 3.14 not found",
|
||||
fields: fields{family: Alpine, release: "3.14"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: false,
|
||||
},
|
||||
// freebsd
|
||||
{
|
||||
name: "freebsd 11 supported",
|
||||
fields: fields{family: FreeBSD, release: "11"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "freebsd 11 eol on 2021-9-30",
|
||||
fields: fields{family: FreeBSD, release: "11"},
|
||||
now: time.Date(2021, 10, 1, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: true,
|
||||
extEnded: true,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "freebsd 12 supported",
|
||||
fields: fields{family: FreeBSD, release: "12"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "freebsd 13 supported",
|
||||
fields: fields{family: FreeBSD, release: "13"},
|
||||
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "freebsd 10 eol",
|
||||
fields: fields{family: FreeBSD, release: "10"},
|
||||
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: true,
|
||||
extEnded: true,
|
||||
found: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
eol, found := GetEOL(tt.fields.family, tt.fields.release)
|
||||
if found != tt.found {
|
||||
t.Errorf("GetEOL.found = %v, want %v", found, tt.found)
|
||||
}
|
||||
if found {
|
||||
if got := eol.IsStandardSupportEnded(tt.now); got != tt.stdEnded {
|
||||
t.Errorf("EOL.IsStandardSupportEnded() = %v, want %v", got, tt.stdEnded)
|
||||
}
|
||||
if got := eol.IsExtendedSuppportEnded(tt.now); got != tt.extEnded {
|
||||
t.Errorf("EOL.IsExtendedSupportEnded() = %v, want %v", got, tt.extEnded)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_majorDotMinor(t *testing.T) {
|
||||
type args struct {
|
||||
osVer string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantMajorDotMinor string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
args: args{
|
||||
osVer: "",
|
||||
},
|
||||
wantMajorDotMinor: "",
|
||||
},
|
||||
{
|
||||
name: "major",
|
||||
args: args{
|
||||
osVer: "3",
|
||||
},
|
||||
wantMajorDotMinor: "3",
|
||||
},
|
||||
{
|
||||
name: "major dot minor",
|
||||
args: args{
|
||||
osVer: "3.1",
|
||||
},
|
||||
wantMajorDotMinor: "3.1",
|
||||
},
|
||||
{
|
||||
name: "major dot minor dot release",
|
||||
args: args{
|
||||
osVer: "3.1.4",
|
||||
},
|
||||
wantMajorDotMinor: "3.1",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if gotMajorDotMinor := majorDotMinor(tt.args.osVer); gotMajorDotMinor != tt.wantMajorDotMinor {
|
||||
t.Errorf("majorDotMinor() = %v, want %v", gotMajorDotMinor, tt.wantMajorDotMinor)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
222
config/portscan.go
Normal file
222
config/portscan.go
Normal file
@@ -0,0 +1,222 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// PortScanConf is the setting for using an external port scanner
|
||||
type PortScanConf struct {
|
||||
IsUseExternalScanner bool `toml:"-" json:"-"`
|
||||
|
||||
// Path to external scanner
|
||||
ScannerBinPath string `toml:"scannerBinPath,omitempty" json:"scannerBinPath,omitempty"`
|
||||
|
||||
// set user has privileged
|
||||
HasPrivileged bool `toml:"hasPrivileged,omitempty" json:"hasPrivileged,omitempty"`
|
||||
|
||||
// set the ScanTechniques for ScannerBinPath
|
||||
ScanTechniques []string `toml:"scanTechniques,omitempty" json:"scanTechniques,omitempty"`
|
||||
|
||||
// set the FIREWALL/IDS EVASION AND SPOOFING(Use given port number)
|
||||
SourcePort string `toml:"sourcePort,omitempty" json:"sourcePort,omitempty"`
|
||||
}
|
||||
|
||||
// ScanTechnique is implemented to represent the supported ScanTechniques in an Enum.
|
||||
type ScanTechnique int
|
||||
|
||||
const (
|
||||
// NotSupportTechnique is a ScanTechnique that is currently not supported.
|
||||
NotSupportTechnique ScanTechnique = iota
|
||||
// TCPSYN is SYN scan
|
||||
TCPSYN
|
||||
// TCPConnect is TCP connect scan
|
||||
TCPConnect
|
||||
// TCPACK is ACK scan
|
||||
TCPACK
|
||||
// TCPWindow is Window scan
|
||||
TCPWindow
|
||||
// TCPMaimon is Maimon scan
|
||||
TCPMaimon
|
||||
// TCPNull is Null scan
|
||||
TCPNull
|
||||
// TCPFIN is FIN scan
|
||||
TCPFIN
|
||||
// TCPXmas is Xmas scan
|
||||
TCPXmas
|
||||
)
|
||||
|
||||
var scanTechniqueMap = map[ScanTechnique]string{
|
||||
TCPSYN: "sS",
|
||||
TCPConnect: "sT",
|
||||
TCPACK: "sA",
|
||||
TCPWindow: "sW",
|
||||
TCPMaimon: "sM",
|
||||
TCPNull: "sN",
|
||||
TCPFIN: "sF",
|
||||
TCPXmas: "sX",
|
||||
}
|
||||
|
||||
func (s ScanTechnique) String() string {
|
||||
switch s {
|
||||
case TCPSYN:
|
||||
return "TCPSYN"
|
||||
case TCPConnect:
|
||||
return "TCPConnect"
|
||||
case TCPACK:
|
||||
return "TCPACK"
|
||||
case TCPWindow:
|
||||
return "TCPWindow"
|
||||
case TCPMaimon:
|
||||
return "TCPMaimon"
|
||||
case TCPNull:
|
||||
return "TCPNull"
|
||||
case TCPFIN:
|
||||
return "TCPFIN"
|
||||
case TCPXmas:
|
||||
return "TCPXmas"
|
||||
default:
|
||||
return "NotSupportTechnique"
|
||||
}
|
||||
}
|
||||
|
||||
// GetScanTechniques converts ScanTechniques loaded from config.toml to []scanTechniques.
|
||||
func (c *PortScanConf) GetScanTechniques() []ScanTechnique {
|
||||
if len(c.ScanTechniques) == 0 {
|
||||
return []ScanTechnique{}
|
||||
}
|
||||
|
||||
scanTechniques := []ScanTechnique{}
|
||||
for _, technique := range c.ScanTechniques {
|
||||
findScanTechniqueFlag := false
|
||||
for key, value := range scanTechniqueMap {
|
||||
if strings.EqualFold(value, technique) {
|
||||
scanTechniques = append(scanTechniques, key)
|
||||
findScanTechniqueFlag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !findScanTechniqueFlag {
|
||||
scanTechniques = append(scanTechniques, NotSupportTechnique)
|
||||
}
|
||||
}
|
||||
|
||||
if len(scanTechniques) == 0 {
|
||||
return []ScanTechnique{NotSupportTechnique}
|
||||
}
|
||||
return scanTechniques
|
||||
}
|
||||
|
||||
// Validate validates configuration
|
||||
func (c *PortScanConf) Validate() (errs []error) {
|
||||
if !c.IsUseExternalScanner {
|
||||
if c.IsZero() {
|
||||
return
|
||||
}
|
||||
errs = append(errs, xerrors.New("To enable the PortScan option, ScannerBinPath must be set."))
|
||||
}
|
||||
|
||||
if _, err := os.Stat(c.ScannerBinPath); err != nil {
|
||||
errs = append(errs, xerrors.Errorf(
|
||||
"scanner is not found. ScannerBinPath: %s not exists", c.ScannerBinPath))
|
||||
}
|
||||
|
||||
scanTechniques := c.GetScanTechniques()
|
||||
for _, scanTechnique := range scanTechniques {
|
||||
if scanTechnique == NotSupportTechnique {
|
||||
errs = append(errs, xerrors.New("There is an unsupported option in ScanTechniques."))
|
||||
}
|
||||
}
|
||||
|
||||
// It does not currently support multiple ScanTechniques.
|
||||
// But if it supports UDP scanning, it will need to accept multiple ScanTechniques.
|
||||
if len(scanTechniques) > 1 {
|
||||
errs = append(errs, xerrors.New("Currently multiple ScanTechniques are not supported."))
|
||||
}
|
||||
|
||||
if c.HasPrivileged {
|
||||
if os.Geteuid() != 0 {
|
||||
output, err := exec.Command("getcap", c.ScannerBinPath).Output()
|
||||
if err != nil {
|
||||
errs = append(errs, xerrors.Errorf("Failed to check capability of %s. error message: %w", c.ScannerBinPath, err))
|
||||
} else {
|
||||
parseOutput := strings.SplitN(string(output), "=", 2)
|
||||
if len(parseOutput) != 2 {
|
||||
errs = append(errs, xerrors.Errorf("Failed to parse getcap outputs. please execute this command: `$ getcap %s`. If the following string (`/usr/bin/nmap = ... `) is not displayed, you need to set the capability with the following command. `$ setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip %s`", c.ScannerBinPath, c.ScannerBinPath))
|
||||
} else {
|
||||
parseCapability := strings.Split(strings.TrimSpace(parseOutput[1]), "+")
|
||||
capabilities := strings.Split(parseCapability[0], ",")
|
||||
for _, needCap := range []string{"cap_net_bind_service", "cap_net_admin", "cap_net_raw"} {
|
||||
existCapFlag := false
|
||||
for _, cap := range capabilities {
|
||||
if needCap == cap {
|
||||
existCapFlag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if existCapFlag {
|
||||
continue
|
||||
}
|
||||
|
||||
errs = append(errs, xerrors.Errorf("Not enough capability to execute. needs: ['cap_net_bind_service', 'cap_net_admin', 'cap_net_raw'], actual: %s. To fix this, run the following command. `$ setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip %s`", capabilities, c.ScannerBinPath))
|
||||
break
|
||||
}
|
||||
|
||||
if parseCapability[1] != "eip" {
|
||||
errs = append(errs, xerrors.Errorf("Capability(`cap_net_bind_service,cap_net_admin,cap_net_raw`) must belong to the following capability set(need: eip, actual: %s). To fix this, run the following command. `$ setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip %s`", parseCapability[1], c.ScannerBinPath))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !c.HasPrivileged {
|
||||
for _, scanTechnique := range scanTechniques {
|
||||
if scanTechnique != TCPConnect && scanTechnique != NotSupportTechnique {
|
||||
errs = append(errs, xerrors.New("If not privileged, only TCPConnect Scan(-sT) can be used."))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if c.SourcePort != "" {
|
||||
for _, scanTechnique := range scanTechniques {
|
||||
if scanTechnique == TCPConnect {
|
||||
errs = append(errs, xerrors.New("SourcePort Option(-g/--source-port) is incompatible with the default TCPConnect Scan(-sT)."))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
portNumber, err := strconv.Atoi(c.SourcePort)
|
||||
if err != nil {
|
||||
errs = append(errs, xerrors.Errorf("SourcePort conversion failed. %w", err))
|
||||
} else {
|
||||
if portNumber < 0 || 65535 < portNumber {
|
||||
errs = append(errs, xerrors.Errorf("SourcePort(%s) must be between 0 and 65535.", c.SourcePort))
|
||||
}
|
||||
|
||||
if portNumber == 0 {
|
||||
errs = append(errs, xerrors.New("SourcePort(0) may not work on all systems."))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err := govalidator.ValidateStruct(c)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// IsZero return whether this struct is not specified in config.toml
|
||||
func (c PortScanConf) IsZero() bool {
|
||||
return c.ScannerBinPath == "" && !c.HasPrivileged && len(c.ScanTechniques) == 0 && c.SourcePort == ""
|
||||
}
|
||||
69
config/portscan_test.go
Normal file
69
config/portscan_test.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPortScanConf_getScanTechniques(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
techniques []string
|
||||
want []ScanTechnique
|
||||
}{
|
||||
{
|
||||
name: "nil",
|
||||
techniques: []string{},
|
||||
want: []ScanTechnique{},
|
||||
},
|
||||
{
|
||||
name: "single",
|
||||
techniques: []string{"sS"},
|
||||
want: []ScanTechnique{TCPSYN},
|
||||
},
|
||||
{
|
||||
name: "multiple",
|
||||
techniques: []string{"sS", "sT"},
|
||||
want: []ScanTechnique{TCPSYN, TCPConnect},
|
||||
},
|
||||
{
|
||||
name: "unknown",
|
||||
techniques: []string{"sU"},
|
||||
want: []ScanTechnique{NotSupportTechnique},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := PortScanConf{ScanTechniques: tt.techniques}
|
||||
if got := c.GetScanTechniques(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("PortScanConf.getScanTechniques() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPortScanConf_IsZero(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
conf PortScanConf
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "not zero",
|
||||
conf: PortScanConf{ScannerBinPath: "/usr/bin/nmap"},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "zero",
|
||||
conf: PortScanConf{},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.conf.IsZero(); got != tt.want {
|
||||
t.Errorf("PortScanConf.IsZero() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
34
config/saasconf.go
Normal file
34
config/saasconf.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/asaskevich/govalidator"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// SaasConf is FutureVuls config
|
||||
type SaasConf struct {
|
||||
GroupID int64 `json:"-"`
|
||||
Token string `json:"-"`
|
||||
URL string `json:"-"`
|
||||
}
|
||||
|
||||
// Validate validates configuration
|
||||
func (c *SaasConf) Validate() (errs []error) {
|
||||
if c.GroupID == 0 {
|
||||
errs = append(errs, xerrors.New("GroupID must not be empty"))
|
||||
}
|
||||
|
||||
if len(c.Token) == 0 {
|
||||
errs = append(errs, xerrors.New("Token must not be empty"))
|
||||
}
|
||||
|
||||
if len(c.URL) == 0 {
|
||||
errs = append(errs, xerrors.New("URL must not be empty"))
|
||||
}
|
||||
|
||||
_, err := govalidator.ValidateStruct(c)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
110
config/scanmode.go
Normal file
110
config/scanmode.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// ScanMode has a type of scan mode. fast, fast-root, deep and offline
|
||||
type ScanMode struct {
|
||||
flag byte
|
||||
}
|
||||
|
||||
const (
|
||||
// Fast is fast scan mode
|
||||
Fast = byte(1 << iota)
|
||||
// FastRoot is scanmode
|
||||
FastRoot
|
||||
// Deep is scanmode
|
||||
Deep
|
||||
// Offline is scanmode
|
||||
Offline
|
||||
|
||||
fastStr = "fast"
|
||||
fastRootStr = "fast-root"
|
||||
deepStr = "deep"
|
||||
offlineStr = "offline"
|
||||
)
|
||||
|
||||
// Set mode
|
||||
func (s *ScanMode) Set(f byte) {
|
||||
s.flag |= f
|
||||
}
|
||||
|
||||
// IsFast return whether scan mode is fast
|
||||
func (s ScanMode) IsFast() bool {
|
||||
return s.flag&Fast == Fast
|
||||
}
|
||||
|
||||
// IsFastRoot return whether scan mode is fastroot
|
||||
func (s ScanMode) IsFastRoot() bool {
|
||||
return s.flag&FastRoot == FastRoot
|
||||
}
|
||||
|
||||
// IsDeep return whether scan mode is deep
|
||||
func (s ScanMode) IsDeep() bool {
|
||||
return s.flag&Deep == Deep
|
||||
}
|
||||
|
||||
// IsOffline return whether scan mode is offline
|
||||
func (s ScanMode) IsOffline() bool {
|
||||
return s.flag&Offline == Offline
|
||||
}
|
||||
|
||||
func (s *ScanMode) ensure() error {
|
||||
numTrue := 0
|
||||
for _, b := range []bool{s.IsFast(), s.IsFastRoot(), s.IsDeep()} {
|
||||
if b {
|
||||
numTrue++
|
||||
}
|
||||
}
|
||||
if numTrue == 0 {
|
||||
s.Set(Fast)
|
||||
} else if s.IsDeep() && s.IsOffline() {
|
||||
return xerrors.New("Don't specify both of deep and offline")
|
||||
} else if numTrue != 1 {
|
||||
return xerrors.New("Specify only one of offline, fast, fast-root or deep")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s ScanMode) String() string {
|
||||
ss := ""
|
||||
if s.IsFast() {
|
||||
ss = fastStr
|
||||
} else if s.IsFastRoot() {
|
||||
ss = fastRootStr
|
||||
} else if s.IsDeep() {
|
||||
ss = deepStr
|
||||
}
|
||||
if s.IsOffline() {
|
||||
ss += " " + offlineStr
|
||||
}
|
||||
return ss + " mode"
|
||||
}
|
||||
|
||||
func setScanMode(server *ServerInfo) error {
|
||||
if len(server.ScanMode) == 0 {
|
||||
server.ScanMode = Conf.Default.ScanMode
|
||||
}
|
||||
for _, m := range server.ScanMode {
|
||||
switch strings.ToLower(m) {
|
||||
case fastStr:
|
||||
server.Mode.Set(Fast)
|
||||
case fastRootStr:
|
||||
server.Mode.Set(FastRoot)
|
||||
case deepStr:
|
||||
server.Mode.Set(Deep)
|
||||
case offlineStr:
|
||||
server.Mode.Set(Offline)
|
||||
default:
|
||||
return xerrors.Errorf("scanMode: %s of %s is invalid. Specify -fast, -fast-root, -deep or offline",
|
||||
m, server.ServerName)
|
||||
}
|
||||
}
|
||||
if err := server.Mode.ensure(); err != nil {
|
||||
return xerrors.Errorf("%s in %s", err, server.ServerName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
97
config/scanmodule.go
Normal file
97
config/scanmodule.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// ScanModule has a type of scan module
|
||||
type ScanModule struct {
|
||||
flag byte
|
||||
}
|
||||
|
||||
const (
|
||||
// OSPkg is scanmodule
|
||||
OSPkg = byte(1 << iota)
|
||||
// WordPress is scanmodule
|
||||
WordPress
|
||||
// Lockfile is scanmodule
|
||||
Lockfile
|
||||
// Port is scanmodule
|
||||
Port
|
||||
|
||||
osPkgStr = "ospkg"
|
||||
wordPressStr = "wordpress"
|
||||
lockfileStr = "lockfile"
|
||||
portStr = "port"
|
||||
)
|
||||
|
||||
var allModules = []string{osPkgStr, wordPressStr, lockfileStr, portStr}
|
||||
|
||||
// Set module
|
||||
func (s *ScanModule) Set(f byte) {
|
||||
s.flag |= f
|
||||
}
|
||||
|
||||
// IsScanOSPkg return whether scanning os pkg
|
||||
func (s ScanModule) IsScanOSPkg() bool {
|
||||
return s.flag&OSPkg == OSPkg
|
||||
}
|
||||
|
||||
// IsScanWordPress return whether scanning wordpress
|
||||
func (s ScanModule) IsScanWordPress() bool {
|
||||
return s.flag&WordPress == WordPress
|
||||
}
|
||||
|
||||
// IsScanLockFile whether scanning lock file
|
||||
func (s ScanModule) IsScanLockFile() bool {
|
||||
return s.flag&Lockfile == Lockfile
|
||||
}
|
||||
|
||||
// IsScanPort whether scanning listening ports
|
||||
func (s ScanModule) IsScanPort() bool {
|
||||
return s.flag&Port == Port
|
||||
}
|
||||
|
||||
// IsZero return the struct value are all false
|
||||
func (s ScanModule) IsZero() bool {
|
||||
return !(s.IsScanOSPkg() || s.IsScanWordPress() || s.IsScanLockFile() || s.IsScanPort())
|
||||
}
|
||||
|
||||
func (s *ScanModule) ensure() error {
|
||||
if s.IsZero() {
|
||||
s.Set(OSPkg)
|
||||
s.Set(WordPress)
|
||||
s.Set(Lockfile)
|
||||
s.Set(Port)
|
||||
} else if !s.IsScanOSPkg() && s.IsScanPort() {
|
||||
return xerrors.New("When specifying the Port, Specify OSPkg as well")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setScanModules(server *ServerInfo, d ServerInfo) error {
|
||||
if len(server.ScanModules) == 0 {
|
||||
server.ScanModules = d.ScanModules
|
||||
}
|
||||
for _, m := range server.ScanModules {
|
||||
switch strings.ToLower(m) {
|
||||
case osPkgStr:
|
||||
server.Module.Set(OSPkg)
|
||||
case wordPressStr:
|
||||
server.Module.Set(WordPress)
|
||||
case lockfileStr:
|
||||
server.Module.Set(Lockfile)
|
||||
case portStr:
|
||||
server.Module.Set(Port)
|
||||
default:
|
||||
return xerrors.Errorf("scanMode: %s of %s is invalid. Specify %s",
|
||||
m, server.ServerName, allModules)
|
||||
}
|
||||
}
|
||||
if err := server.Module.ensure(); err != nil {
|
||||
return xerrors.Errorf("%s in %s", err, server.ServerName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
65
config/scanmodule_test.go
Normal file
65
config/scanmodule_test.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestScanModule_IsZero(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
modes []byte
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "not zero",
|
||||
modes: []byte{OSPkg},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "zero",
|
||||
modes: []byte{},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := ScanModule{}
|
||||
for _, b := range tt.modes {
|
||||
s.Set(b)
|
||||
}
|
||||
if got := s.IsZero(); got != tt.want {
|
||||
t.Errorf("ScanModule.IsZero() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestScanModule_validate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
modes []byte
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
modes: []byte{},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "err",
|
||||
modes: []byte{WordPress, Lockfile, Port},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := ScanModule{}
|
||||
for _, b := range tt.modes {
|
||||
s.Set(b)
|
||||
}
|
||||
if err := s.ensure(); (err != nil) != tt.wantErr {
|
||||
t.Errorf("ScanModule.validate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
52
config/slackconf.go
Normal file
52
config/slackconf.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// SlackConf is slack config
|
||||
type SlackConf struct {
|
||||
HookURL string `valid:"url" json:"-" toml:"hookURL,omitempty"`
|
||||
LegacyToken string `json:"-" toml:"legacyToken,omitempty"`
|
||||
Channel string `json:"-" toml:"channel,omitempty"`
|
||||
IconEmoji string `json:"-" toml:"iconEmoji,omitempty"`
|
||||
AuthUser string `json:"-" toml:"authUser,omitempty"`
|
||||
NotifyUsers []string `toml:"notifyUsers,omitempty" json:"-"`
|
||||
Text string `json:"-"`
|
||||
Enabled bool `toml:"-" json:"-"`
|
||||
}
|
||||
|
||||
// Validate validates configuration
|
||||
func (c *SlackConf) Validate() (errs []error) {
|
||||
if !c.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
if len(c.HookURL) == 0 && len(c.LegacyToken) == 0 {
|
||||
errs = append(errs, xerrors.New("slack.hookURL or slack.LegacyToken must not be empty"))
|
||||
}
|
||||
|
||||
if len(c.Channel) == 0 {
|
||||
errs = append(errs, xerrors.New("slack.channel must not be empty"))
|
||||
} else {
|
||||
if !(strings.HasPrefix(c.Channel, "#") ||
|
||||
c.Channel == "${servername}") {
|
||||
errs = append(errs, xerrors.Errorf(
|
||||
"channel's prefix must be '#', channel: %s", c.Channel))
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.AuthUser) == 0 {
|
||||
errs = append(errs, xerrors.New("slack.authUser must not be empty"))
|
||||
}
|
||||
|
||||
_, err := govalidator.ValidateStruct(c)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
65
config/smtpconf.go
Normal file
65
config/smtpconf.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/asaskevich/govalidator"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// SMTPConf is smtp config
|
||||
type SMTPConf struct {
|
||||
SMTPAddr string `toml:"smtpAddr,omitempty" json:"-"`
|
||||
SMTPPort string `toml:"smtpPort,omitempty" valid:"port" json:"-"`
|
||||
User string `toml:"user,omitempty" json:"-"`
|
||||
Password string `toml:"password,omitempty" json:"-"`
|
||||
From string `toml:"from,omitempty" json:"-"`
|
||||
To []string `toml:"to,omitempty" json:"-"`
|
||||
Cc []string `toml:"cc,omitempty" json:"-"`
|
||||
SubjectPrefix string `toml:"subjectPrefix,omitempty" json:"-"`
|
||||
Enabled bool `toml:"-" json:"-"`
|
||||
}
|
||||
|
||||
func checkEmails(emails []string) (errs []error) {
|
||||
for _, addr := range emails {
|
||||
if len(addr) == 0 {
|
||||
return
|
||||
}
|
||||
if ok := govalidator.IsEmail(addr); !ok {
|
||||
errs = append(errs, xerrors.Errorf("Invalid email address. email: %s", addr))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Validate SMTP configuration
|
||||
func (c *SMTPConf) Validate() (errs []error) {
|
||||
if !c.Enabled {
|
||||
return
|
||||
}
|
||||
emails := []string{}
|
||||
emails = append(emails, c.From)
|
||||
emails = append(emails, c.To...)
|
||||
emails = append(emails, c.Cc...)
|
||||
|
||||
if emailErrs := checkEmails(emails); 0 < len(emailErrs) {
|
||||
errs = append(errs, emailErrs...)
|
||||
}
|
||||
|
||||
if c.SMTPAddr == "" {
|
||||
errs = append(errs, xerrors.New("email.smtpAddr must not be empty"))
|
||||
}
|
||||
if c.SMTPPort == "" {
|
||||
errs = append(errs, xerrors.New("email.smtpPort must not be empty"))
|
||||
}
|
||||
if len(c.To) == 0 {
|
||||
errs = append(errs, xerrors.New("email.To required at least one address"))
|
||||
}
|
||||
if len(c.From) == 0 {
|
||||
errs = append(errs, xerrors.New("email.From required at least one address"))
|
||||
}
|
||||
|
||||
_, err := govalidator.ValidateStruct(c)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
130
config/syslogconf.go
Normal file
130
config/syslogconf.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log/syslog"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// SyslogConf is syslog config
|
||||
type SyslogConf struct {
|
||||
Protocol string `json:"-"`
|
||||
Host string `valid:"host" json:"-"`
|
||||
Port string `valid:"port" json:"-"`
|
||||
Severity string `json:"-"`
|
||||
Facility string `json:"-"`
|
||||
Tag string `json:"-"`
|
||||
Verbose bool `json:"-"`
|
||||
Enabled bool `toml:"-" json:"-"`
|
||||
}
|
||||
|
||||
// Validate validates configuration
|
||||
func (c *SyslogConf) Validate() (errs []error) {
|
||||
if !c.Enabled {
|
||||
return nil
|
||||
}
|
||||
// If protocol is empty, it will connect to the local syslog server.
|
||||
if len(c.Protocol) > 0 && c.Protocol != "tcp" && c.Protocol != "udp" {
|
||||
errs = append(errs, errors.New(`syslog.protocol must be "tcp" or "udp"`))
|
||||
}
|
||||
|
||||
// Default port: 514
|
||||
if c.Port == "" {
|
||||
c.Port = "514"
|
||||
}
|
||||
|
||||
if _, err := c.GetSeverity(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
if _, err := c.GetFacility(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
if _, err := govalidator.ValidateStruct(c); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// GetSeverity gets severity
|
||||
func (c *SyslogConf) GetSeverity() (syslog.Priority, error) {
|
||||
if c.Severity == "" {
|
||||
return syslog.LOG_INFO, nil
|
||||
}
|
||||
|
||||
switch c.Severity {
|
||||
case "emerg":
|
||||
return syslog.LOG_EMERG, nil
|
||||
case "alert":
|
||||
return syslog.LOG_ALERT, nil
|
||||
case "crit":
|
||||
return syslog.LOG_CRIT, nil
|
||||
case "err":
|
||||
return syslog.LOG_ERR, nil
|
||||
case "warning":
|
||||
return syslog.LOG_WARNING, nil
|
||||
case "notice":
|
||||
return syslog.LOG_NOTICE, nil
|
||||
case "info":
|
||||
return syslog.LOG_INFO, nil
|
||||
case "debug":
|
||||
return syslog.LOG_DEBUG, nil
|
||||
default:
|
||||
return -1, xerrors.Errorf("Invalid severity: %s", c.Severity)
|
||||
}
|
||||
}
|
||||
|
||||
// GetFacility gets facility
|
||||
func (c *SyslogConf) GetFacility() (syslog.Priority, error) {
|
||||
if c.Facility == "" {
|
||||
return syslog.LOG_AUTH, nil
|
||||
}
|
||||
|
||||
switch c.Facility {
|
||||
case "kern":
|
||||
return syslog.LOG_KERN, nil
|
||||
case "user":
|
||||
return syslog.LOG_USER, nil
|
||||
case "mail":
|
||||
return syslog.LOG_MAIL, nil
|
||||
case "daemon":
|
||||
return syslog.LOG_DAEMON, nil
|
||||
case "auth":
|
||||
return syslog.LOG_AUTH, nil
|
||||
case "syslog":
|
||||
return syslog.LOG_SYSLOG, nil
|
||||
case "lpr":
|
||||
return syslog.LOG_LPR, nil
|
||||
case "news":
|
||||
return syslog.LOG_NEWS, nil
|
||||
case "uucp":
|
||||
return syslog.LOG_UUCP, nil
|
||||
case "cron":
|
||||
return syslog.LOG_CRON, nil
|
||||
case "authpriv":
|
||||
return syslog.LOG_AUTHPRIV, nil
|
||||
case "ftp":
|
||||
return syslog.LOG_FTP, nil
|
||||
case "local0":
|
||||
return syslog.LOG_LOCAL0, nil
|
||||
case "local1":
|
||||
return syslog.LOG_LOCAL1, nil
|
||||
case "local2":
|
||||
return syslog.LOG_LOCAL2, nil
|
||||
case "local3":
|
||||
return syslog.LOG_LOCAL3, nil
|
||||
case "local4":
|
||||
return syslog.LOG_LOCAL4, nil
|
||||
case "local5":
|
||||
return syslog.LOG_LOCAL5, nil
|
||||
case "local6":
|
||||
return syslog.LOG_LOCAL6, nil
|
||||
case "local7":
|
||||
return syslog.LOG_LOCAL7, nil
|
||||
default:
|
||||
return -1, xerrors.Errorf("Invalid facility: %s", c.Facility)
|
||||
}
|
||||
}
|
||||
33
config/telegramconf.go
Normal file
33
config/telegramconf.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/asaskevich/govalidator"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// TelegramConf is Telegram config
|
||||
type TelegramConf struct {
|
||||
Token string `json:"-"`
|
||||
ChatID string `json:"-"`
|
||||
Enabled bool `toml:"-" json:"-"`
|
||||
}
|
||||
|
||||
// Validate validates configuration
|
||||
func (c *TelegramConf) Validate() (errs []error) {
|
||||
if !c.Enabled {
|
||||
return
|
||||
}
|
||||
if len(c.ChatID) == 0 {
|
||||
errs = append(errs, xerrors.New("TelegramConf.ChatID must not be empty"))
|
||||
}
|
||||
|
||||
if len(c.Token) == 0 {
|
||||
errs = append(errs, xerrors.New("TelegramConf.Token must not be empty"))
|
||||
}
|
||||
|
||||
_, err := govalidator.ValidateStruct(c)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,30 +1,13 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/future-architect/vuls/constant"
|
||||
"github.com/knqyf263/go-cpe/naming"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// TOMLLoader loads config
|
||||
@@ -32,249 +15,218 @@ 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 {
|
||||
func (c TOMLLoader) Load(pathToToml, _ string) error {
|
||||
// util.Log.Infof("Loading config: %s", pathToToml)
|
||||
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
|
||||
|
||||
d := conf.Default
|
||||
Conf.Default = d
|
||||
servers := make(map[string]ServerInfo)
|
||||
|
||||
if keyPass != "" {
|
||||
d.KeyPassword = keyPass
|
||||
for _, cnf := range []VulnDictInterface{
|
||||
&Conf.CveDict,
|
||||
&Conf.OvalDict,
|
||||
&Conf.Gost,
|
||||
&Conf.Exploit,
|
||||
&Conf.Metasploit,
|
||||
} {
|
||||
cnf.Init()
|
||||
}
|
||||
|
||||
i := 0
|
||||
for serverName, v := range conf.Servers {
|
||||
if 0 < len(v.KeyPassword) {
|
||||
return fmt.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)
|
||||
index := 0
|
||||
for name, server := range Conf.Servers {
|
||||
server.ServerName = name
|
||||
if err := setDefaultIfEmpty(&server); err != nil {
|
||||
return xerrors.Errorf("Failed to set default value to config. server: %s, err: %w", name, err)
|
||||
}
|
||||
|
||||
s := ServerInfo{ServerName: serverName}
|
||||
if v.Type != ServerTypePseudo {
|
||||
s.Host = v.Host
|
||||
if len(s.Host) == 0 {
|
||||
return fmt.Errorf("%s is invalid. host is empty", serverName)
|
||||
}
|
||||
|
||||
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 fmt.Errorf("%s is invalid. User is empty", serverName)
|
||||
}
|
||||
}
|
||||
|
||||
s.KeyPath = v.KeyPath
|
||||
if len(s.KeyPath) == 0 {
|
||||
s.KeyPath = d.KeyPath
|
||||
}
|
||||
if s.KeyPath != "" {
|
||||
if _, err := os.Stat(s.KeyPath); err != nil {
|
||||
return fmt.Errorf(
|
||||
"%s is invalid. keypath: %s not exists", serverName, s.KeyPath)
|
||||
}
|
||||
}
|
||||
|
||||
s.KeyPassword = v.KeyPassword
|
||||
if len(s.KeyPassword) == 0 {
|
||||
s.KeyPassword = d.KeyPassword
|
||||
}
|
||||
if err := setScanMode(&server); err != nil {
|
||||
return xerrors.Errorf("Failed to set ScanMode: %w", err)
|
||||
}
|
||||
|
||||
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 fmt.Errorf("scanMode: %s of %s is invalie. Specify -fast, -fast-root, -deep or offline", m, serverName)
|
||||
}
|
||||
}
|
||||
if err := s.Mode.validate(); err != nil {
|
||||
return fmt.Errorf("%s in %s", err, serverName)
|
||||
if err := setScanModules(&server, Conf.Default); err != nil {
|
||||
return xerrors.Errorf("Failed to set ScanModule: %w", err)
|
||||
}
|
||||
|
||||
s.CpeNames = v.CpeNames
|
||||
if len(s.CpeNames) == 0 {
|
||||
s.CpeNames = d.CpeNames
|
||||
if len(server.CpeNames) == 0 {
|
||||
server.CpeNames = Conf.Default.CpeNames
|
||||
}
|
||||
|
||||
for i, n := range s.CpeNames {
|
||||
for i, n := range server.CpeNames {
|
||||
uri, err := toCpeURI(n)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to parse CPENames %s in %s: %s", n, serverName, err)
|
||||
return xerrors.Errorf("Failed to parse CPENames %s in %s, err: %w", n, name, err)
|
||||
}
|
||||
s.CpeNames[i] = uri
|
||||
server.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 fmt.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 {
|
||||
for _, cve := range Conf.Default.IgnoreCves {
|
||||
found := false
|
||||
for _, c := range s.IgnoreCves {
|
||||
for _, c := range server.IgnoreCves {
|
||||
if cve == c {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
s.IgnoreCves = append(s.IgnoreCves, cve)
|
||||
server.IgnoreCves = append(server.IgnoreCves, cve)
|
||||
}
|
||||
}
|
||||
|
||||
s.IgnorePkgsRegexp = v.IgnorePkgsRegexp
|
||||
for _, pkg := range d.IgnorePkgsRegexp {
|
||||
for _, pkg := range Conf.Default.IgnorePkgsRegexp {
|
||||
found := false
|
||||
for _, p := range s.IgnorePkgsRegexp {
|
||||
for _, p := range server.IgnorePkgsRegexp {
|
||||
if pkg == p {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
s.IgnorePkgsRegexp = append(s.IgnorePkgsRegexp, pkg)
|
||||
server.IgnorePkgsRegexp = append(server.IgnorePkgsRegexp, pkg)
|
||||
}
|
||||
}
|
||||
for _, reg := range s.IgnorePkgsRegexp {
|
||||
for _, reg := range server.IgnorePkgsRegexp {
|
||||
_, err := regexp.Compile(reg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Faild to parse %s in %s. err: %s", reg, serverName, err)
|
||||
return xerrors.Errorf("Failed to parse %s in %s. err: %w", reg, name, err)
|
||||
}
|
||||
}
|
||||
for contName, cont := range s.Containers {
|
||||
for contName, cont := range server.Containers {
|
||||
for _, reg := range cont.IgnorePkgsRegexp {
|
||||
_, err := regexp.Compile(reg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Faild to parse %s in %s@%s. err: %s",
|
||||
reg, contName, serverName, err)
|
||||
return xerrors.Errorf("Failed to parse %s in %s@%s. err: %w",
|
||||
reg, contName, name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
opt := map[string]interface{}{}
|
||||
for k, v := range d.Optional {
|
||||
opt[k] = v
|
||||
for ownerRepo, githubSetting := range server.GitHubRepos {
|
||||
if ss := strings.Split(ownerRepo, "/"); len(ss) != 2 {
|
||||
return xerrors.Errorf("Failed to parse GitHub owner/repo: %s in %s",
|
||||
ownerRepo, name)
|
||||
}
|
||||
if githubSetting.Token == "" {
|
||||
return xerrors.Errorf("GitHub owner/repo: %s in %s token is empty",
|
||||
ownerRepo, name)
|
||||
}
|
||||
}
|
||||
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(server.Enablerepo) == 0 {
|
||||
server.Enablerepo = Conf.Default.Enablerepo
|
||||
}
|
||||
if len(s.Enablerepo) != 0 {
|
||||
for _, repo := range s.Enablerepo {
|
||||
if len(server.Enablerepo) != 0 {
|
||||
for _, repo := range server.Enablerepo {
|
||||
switch repo {
|
||||
case "base", "updates":
|
||||
// nop
|
||||
default:
|
||||
return fmt.Errorf(
|
||||
"For now, enablerepo have to be base or updates: %s, servername: %s",
|
||||
s.Enablerepo, serverName)
|
||||
return xerrors.Errorf(
|
||||
"For now, enablerepo have to be base or updates: %s",
|
||||
server.Enablerepo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.GitHubRepos = v.GitHubRepos
|
||||
for ownerRepo, githubSetting := range s.GitHubRepos {
|
||||
if ss := strings.Split(ownerRepo, "/"); len(ss) != 2 {
|
||||
return fmt.Errorf("Failed to parse GitHub owner/repo: %s in %s",
|
||||
ownerRepo, serverName)
|
||||
}
|
||||
if githubSetting.Token == "" {
|
||||
return fmt.Errorf("GitHub owner/repo: %s in %s token is empty",
|
||||
ownerRepo, serverName)
|
||||
if server.PortScan.ScannerBinPath != "" {
|
||||
server.PortScan.IsUseExternalScanner = true
|
||||
}
|
||||
|
||||
server.LogMsgAnsiColor = Colors[index%len(Colors)]
|
||||
index++
|
||||
|
||||
Conf.Servers[name] = server
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setDefaultIfEmpty(server *ServerInfo) error {
|
||||
if server.Type != constant.ServerTypePseudo {
|
||||
if len(server.Host) == 0 {
|
||||
return xerrors.Errorf("server.host is empty")
|
||||
}
|
||||
|
||||
if len(server.JumpServer) == 0 {
|
||||
server.JumpServer = Conf.Default.JumpServer
|
||||
}
|
||||
|
||||
if server.Port == "" {
|
||||
if Conf.Default.Port != "" {
|
||||
server.Port = Conf.Default.Port
|
||||
} else {
|
||||
server.Port = "22"
|
||||
}
|
||||
}
|
||||
|
||||
s.UUIDs = v.UUIDs
|
||||
s.Type = v.Type
|
||||
if server.User == "" {
|
||||
server.User = Conf.Default.User
|
||||
if server.User == "" && server.Port != "local" {
|
||||
return xerrors.Errorf("server.user is empty")
|
||||
}
|
||||
}
|
||||
|
||||
s.LogMsgAnsiColor = Colors[i%len(Colors)]
|
||||
i++
|
||||
if server.SSHConfigPath == "" {
|
||||
server.SSHConfigPath = Conf.Default.SSHConfigPath
|
||||
}
|
||||
|
||||
servers[serverName] = s
|
||||
if server.KeyPath == "" {
|
||||
server.KeyPath = Conf.Default.KeyPath
|
||||
}
|
||||
}
|
||||
Conf.Servers = servers
|
||||
|
||||
if len(server.Lockfiles) == 0 {
|
||||
server.Lockfiles = Conf.Default.Lockfiles
|
||||
}
|
||||
|
||||
if len(server.ContainersIncluded) == 0 {
|
||||
server.ContainersIncluded = Conf.Default.ContainersIncluded
|
||||
}
|
||||
|
||||
if len(server.ContainersExcluded) == 0 {
|
||||
server.ContainersExcluded = Conf.Default.ContainersExcluded
|
||||
}
|
||||
|
||||
if server.ContainerType == "" {
|
||||
server.ContainerType = Conf.Default.ContainerType
|
||||
}
|
||||
|
||||
for contName, cont := range server.Containers {
|
||||
cont.IgnoreCves = append(cont.IgnoreCves, Conf.Default.IgnoreCves...)
|
||||
server.Containers[contName] = cont
|
||||
}
|
||||
|
||||
if server.OwaspDCXMLPath == "" {
|
||||
server.OwaspDCXMLPath = Conf.Default.OwaspDCXMLPath
|
||||
}
|
||||
|
||||
if server.Memo == "" {
|
||||
server.Memo = Conf.Default.Memo
|
||||
}
|
||||
|
||||
if server.WordPress == nil {
|
||||
server.WordPress = Conf.Default.WordPress
|
||||
if server.WordPress == nil {
|
||||
server.WordPress = &WordPressConf{}
|
||||
}
|
||||
}
|
||||
|
||||
if server.PortScan == nil {
|
||||
server.PortScan = Conf.Default.PortScan
|
||||
if server.PortScan == nil {
|
||||
server.PortScan = &PortScanConf{}
|
||||
}
|
||||
}
|
||||
|
||||
if len(server.IgnoredJSONKeys) == 0 {
|
||||
server.IgnoredJSONKeys = Conf.Default.IgnoredJSONKeys
|
||||
}
|
||||
|
||||
opt := map[string]interface{}{}
|
||||
for k, v := range Conf.Default.Optional {
|
||||
opt[k] = v
|
||||
}
|
||||
for k, v := range server.Optional {
|
||||
opt[k] = v
|
||||
}
|
||||
server.Optional = opt
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -292,5 +244,5 @@ func toCpeURI(cpename string) (string, error) {
|
||||
}
|
||||
return naming.BindToURI(wfn), nil
|
||||
}
|
||||
return "", fmt.Errorf("Unknow CPE format: %s", cpename)
|
||||
return "", xerrors.Errorf("Unknown CPE format: %s", cpename)
|
||||
}
|
||||
|
||||
276
config/vulnDictConf.go
Normal file
276
config/vulnDictConf.go
Normal file
@@ -0,0 +1,276 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// VulnDictInterface is an interface of vulnsrc
|
||||
type VulnDictInterface interface {
|
||||
Init()
|
||||
Validate() error
|
||||
IsFetchViaHTTP() bool
|
||||
CheckHTTPHealth() error
|
||||
GetName() string
|
||||
GetType() string
|
||||
GetURL() string
|
||||
GetSQLite3Path() string
|
||||
GetDebugSQL() bool
|
||||
}
|
||||
|
||||
// VulnDict is a base struct of vuln dicts
|
||||
type VulnDict struct {
|
||||
Name string
|
||||
|
||||
// DB type of CVE dictionary (sqlite3, mysql, postgres or redis)
|
||||
Type string
|
||||
|
||||
// http://cve-dictionary.com:1323 or DB connection string
|
||||
URL string `json:"-"`
|
||||
|
||||
// /path/to/cve.sqlite3
|
||||
SQLite3Path string
|
||||
|
||||
DebugSQL bool
|
||||
}
|
||||
|
||||
// GetType returns type
|
||||
func (cnf VulnDict) GetType() string {
|
||||
return cnf.Type
|
||||
}
|
||||
|
||||
// GetName returns name
|
||||
func (cnf VulnDict) GetName() string {
|
||||
return cnf.Name
|
||||
}
|
||||
|
||||
// GetURL returns url
|
||||
func (cnf VulnDict) GetURL() string {
|
||||
return cnf.URL
|
||||
}
|
||||
|
||||
// GetSQLite3Path return the path of SQLite3
|
||||
func (cnf VulnDict) GetSQLite3Path() string {
|
||||
return cnf.SQLite3Path
|
||||
}
|
||||
|
||||
// GetDebugSQL return debugSQL flag
|
||||
func (cnf VulnDict) GetDebugSQL() bool {
|
||||
return cnf.DebugSQL
|
||||
}
|
||||
|
||||
// Validate settings
|
||||
func (cnf VulnDict) Validate() error {
|
||||
logging.Log.Infof("%s.type=%s, %s.url=%s, %s.SQLite3Path=%s",
|
||||
cnf.Name, cnf.Type, cnf.Name, cnf.URL, cnf.Name, cnf.SQLite3Path)
|
||||
|
||||
switch cnf.Type {
|
||||
case "sqlite3":
|
||||
if cnf.URL != "" {
|
||||
return xerrors.Errorf("To use SQLite3, specify %s.type=sqlite3 and %s.SQLite3Path. To use as HTTP server mode, specify %s.type=http and %s.url",
|
||||
cnf.Name, cnf.Name, cnf.Name, cnf.Name)
|
||||
}
|
||||
if ok, _ := govalidator.IsFilePath(cnf.SQLite3Path); !ok {
|
||||
return xerrors.Errorf("SQLite3 path must be a *Absolute* file path. %s.SQLite3Path: %s",
|
||||
cnf.Name, cnf.SQLite3Path)
|
||||
}
|
||||
if _, err := os.Stat(cnf.SQLite3Path); os.IsNotExist(err) {
|
||||
logging.Log.Warnf("%s.SQLite3Path=%s file not found", cnf.Name, cnf.SQLite3Path)
|
||||
}
|
||||
case "mysql":
|
||||
if cnf.URL == "" {
|
||||
return xerrors.Errorf(`MySQL connection string is needed. %s.url="user:pass@tcp(localhost:3306)/dbname"`, cnf.Name)
|
||||
}
|
||||
case "postgres":
|
||||
if cnf.URL == "" {
|
||||
return xerrors.Errorf(`PostgreSQL connection string is needed. %s.url="host=myhost user=user dbname=dbname sslmode=disable password=password"`, cnf.Name)
|
||||
}
|
||||
case "redis":
|
||||
if cnf.URL == "" {
|
||||
return xerrors.Errorf(`Redis connection string is needed. %s.url="redis://localhost/0"`, cnf.Name)
|
||||
}
|
||||
case "http":
|
||||
if cnf.URL == "" {
|
||||
return xerrors.Errorf(`URL is needed. -%s-url="http://localhost:1323"`, cnf.Name)
|
||||
}
|
||||
default:
|
||||
return xerrors.Errorf("%s.type must be either 'sqlite3', 'mysql', 'postgres', 'redis' or 'http'. %s.type: %s", cnf.Name, cnf.Name, cnf.Type)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Init the struct
|
||||
func (cnf VulnDict) Init() {}
|
||||
|
||||
func (cnf *VulnDict) setDefault(sqlite3Name string) {
|
||||
if cnf.Type == "" {
|
||||
cnf.Type = "sqlite3"
|
||||
}
|
||||
if cnf.URL == "" && cnf.SQLite3Path == "" {
|
||||
wd, _ := os.Getwd()
|
||||
cnf.SQLite3Path = filepath.Join(wd, sqlite3Name)
|
||||
}
|
||||
}
|
||||
|
||||
// IsFetchViaHTTP returns if fetch via HTTP
|
||||
func (cnf VulnDict) IsFetchViaHTTP() bool {
|
||||
return cnf.Type == "http"
|
||||
}
|
||||
|
||||
// CheckHTTPHealth checks http server status
|
||||
func (cnf VulnDict) CheckHTTPHealth() error {
|
||||
if !cnf.IsFetchViaHTTP() {
|
||||
return nil
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/health", cnf.URL)
|
||||
resp, _, errs := gorequest.New().Timeout(10 * time.Second).SetDebug(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 CVE server. url: %s, errs: %s",
|
||||
url, errs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GovalDictConf is goval-dictionary config
|
||||
type GovalDictConf struct {
|
||||
VulnDict
|
||||
}
|
||||
|
||||
const govalType = "OVALDB_TYPE"
|
||||
const govalURL = "OVALDB_URL"
|
||||
const govalPATH = "OVALDB_SQLITE3_PATH"
|
||||
|
||||
// Init set options with the following priority.
|
||||
// 1. Environment variable
|
||||
// 2. config.toml
|
||||
func (cnf *GovalDictConf) Init() {
|
||||
cnf.Name = "ovalDict"
|
||||
if os.Getenv(govalType) != "" {
|
||||
cnf.Type = os.Getenv(govalType)
|
||||
}
|
||||
if os.Getenv(govalURL) != "" {
|
||||
cnf.URL = os.Getenv(govalURL)
|
||||
}
|
||||
if os.Getenv(govalPATH) != "" {
|
||||
cnf.SQLite3Path = os.Getenv(govalPATH)
|
||||
}
|
||||
cnf.setDefault("oval.sqlite3")
|
||||
cnf.DebugSQL = Conf.DebugSQL
|
||||
}
|
||||
|
||||
// ExploitConf is exploit config
|
||||
type ExploitConf struct {
|
||||
VulnDict
|
||||
}
|
||||
|
||||
const exploitDBType = "EXPLOITDB_TYPE"
|
||||
const exploitDBURL = "EXPLOITDB_URL"
|
||||
const exploitDBPATH = "EXPLOITDB_SQLITE3_PATH"
|
||||
|
||||
// Init set options with the following priority.
|
||||
// 1. Environment variable
|
||||
// 2. config.toml
|
||||
func (cnf *ExploitConf) Init() {
|
||||
cnf.Name = "exploit"
|
||||
if os.Getenv(exploitDBType) != "" {
|
||||
cnf.Type = os.Getenv(exploitDBType)
|
||||
}
|
||||
if os.Getenv(exploitDBURL) != "" {
|
||||
cnf.URL = os.Getenv(exploitDBURL)
|
||||
}
|
||||
if os.Getenv(exploitDBPATH) != "" {
|
||||
cnf.SQLite3Path = os.Getenv(exploitDBPATH)
|
||||
}
|
||||
cnf.setDefault("go-exploitdb.sqlite3")
|
||||
cnf.DebugSQL = Conf.DebugSQL
|
||||
}
|
||||
|
||||
// GoCveDictConf is GoCveDict config
|
||||
type GoCveDictConf struct {
|
||||
VulnDict
|
||||
}
|
||||
|
||||
const cveDBType = "CVEDB_TYPE"
|
||||
const cveDBURL = "CVEDB_URL"
|
||||
const cveDBPATH = "CVEDB_SQLITE3_PATH"
|
||||
|
||||
// Init set options with the following priority.
|
||||
// 1. Environment variable
|
||||
// 2. config.toml
|
||||
func (cnf *GoCveDictConf) Init() {
|
||||
cnf.Name = "cveDict"
|
||||
if os.Getenv(cveDBType) != "" {
|
||||
cnf.Type = os.Getenv(cveDBType)
|
||||
}
|
||||
if os.Getenv(cveDBURL) != "" {
|
||||
cnf.URL = os.Getenv(cveDBURL)
|
||||
}
|
||||
if os.Getenv(cveDBPATH) != "" {
|
||||
cnf.SQLite3Path = os.Getenv(cveDBPATH)
|
||||
}
|
||||
cnf.setDefault("cve.sqlite3")
|
||||
cnf.DebugSQL = Conf.DebugSQL
|
||||
}
|
||||
|
||||
// GostConf is gost config
|
||||
type GostConf struct {
|
||||
VulnDict
|
||||
}
|
||||
|
||||
const gostDBType = "GOSTDB_TYPE"
|
||||
const gostDBURL = "GOSTDB_URL"
|
||||
const gostDBPATH = "GOSTDB_SQLITE3_PATH"
|
||||
|
||||
// Init set options with the following priority.
|
||||
// 1. Environment variable
|
||||
// 2. config.toml
|
||||
func (cnf *GostConf) Init() {
|
||||
cnf.Name = "gost"
|
||||
if os.Getenv(gostDBType) != "" {
|
||||
cnf.Type = os.Getenv(gostDBType)
|
||||
}
|
||||
if os.Getenv(gostDBURL) != "" {
|
||||
cnf.URL = os.Getenv(gostDBURL)
|
||||
}
|
||||
if os.Getenv(gostDBPATH) != "" {
|
||||
cnf.SQLite3Path = os.Getenv(gostDBPATH)
|
||||
}
|
||||
cnf.setDefault("gost.sqlite3")
|
||||
cnf.DebugSQL = Conf.DebugSQL
|
||||
}
|
||||
|
||||
// MetasploitConf is gost go-metasploitdb
|
||||
type MetasploitConf struct {
|
||||
VulnDict
|
||||
}
|
||||
|
||||
const metasploitDBType = "METASPLOITDB_TYPE"
|
||||
const metasploitDBURL = "METASPLOITDB_URL"
|
||||
const metasploitDBPATH = "METASPLOITDB_SQLITE3_PATH"
|
||||
|
||||
// Init set options with the following priority.
|
||||
// 1. Environment variable
|
||||
// 2. config.toml
|
||||
func (cnf *MetasploitConf) Init() {
|
||||
cnf.Name = "metasploit"
|
||||
if os.Getenv(metasploitDBType) != "" {
|
||||
cnf.Type = os.Getenv(metasploitDBType)
|
||||
}
|
||||
if os.Getenv(metasploitDBURL) != "" {
|
||||
cnf.URL = os.Getenv(metasploitDBURL)
|
||||
}
|
||||
if os.Getenv(metasploitDBPATH) != "" {
|
||||
cnf.SQLite3Path = os.Getenv(metasploitDBPATH)
|
||||
}
|
||||
cnf.setDefault("go-msfdb.sqlite3")
|
||||
cnf.DebugSQL = Conf.DebugSQL
|
||||
}
|
||||
67
constant/constant.go
Normal file
67
constant/constant.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package constant
|
||||
|
||||
// Global constant
|
||||
// Pkg local constants should not be defined here.
|
||||
// Define them in the each package.
|
||||
|
||||
const (
|
||||
// RedHat is
|
||||
RedHat = "redhat"
|
||||
|
||||
// Debian is
|
||||
Debian = "debian"
|
||||
|
||||
// Ubuntu is
|
||||
Ubuntu = "ubuntu"
|
||||
|
||||
// CentOS is
|
||||
CentOS = "centos"
|
||||
|
||||
// Alma is
|
||||
Alma = "alma"
|
||||
|
||||
// Rocky is
|
||||
Rocky = "rocky"
|
||||
|
||||
// Fedora is
|
||||
// Fedora = "fedora"
|
||||
|
||||
// Amazon is
|
||||
Amazon = "amazon"
|
||||
|
||||
// Oracle is
|
||||
Oracle = "oracle"
|
||||
|
||||
// FreeBSD is
|
||||
FreeBSD = "freebsd"
|
||||
|
||||
// Raspbian is
|
||||
Raspbian = "raspbian"
|
||||
|
||||
// Windows is
|
||||
Windows = "windows"
|
||||
|
||||
// OpenSUSE is
|
||||
OpenSUSE = "opensuse"
|
||||
|
||||
// OpenSUSELeap is
|
||||
OpenSUSELeap = "opensuse.leap"
|
||||
|
||||
// SUSEEnterpriseServer is
|
||||
SUSEEnterpriseServer = "suse.linux.enterprise.server"
|
||||
|
||||
// SUSEEnterpriseDesktop is
|
||||
SUSEEnterpriseDesktop = "suse.linux.enterprise.desktop"
|
||||
|
||||
// SUSEOpenstackCloud is
|
||||
SUSEOpenstackCloud = "suse.openstack.cloud"
|
||||
|
||||
// Alpine is
|
||||
Alpine = "alpine"
|
||||
|
||||
// ServerTypePseudo is used for ServerInfo.Type, r.Family
|
||||
ServerTypePseudo = "pseudo"
|
||||
|
||||
// DeepSecurity is
|
||||
DeepSecurity = "deepsecurity"
|
||||
)
|
||||
38
contrib/future-vuls/README.md
Normal file
38
contrib/future-vuls/README.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# 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
|
||||
```
|
||||
98
contrib/future-vuls/cmd/main.go
Normal file
98
contrib/future-vuls/cmd/main.go
Normal file
@@ -0,0 +1,98 @@
|
||||
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/saas"
|
||||
"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 = (saas.Writer{}).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)
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,13 @@ package parser
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/knqyf263/go-cpe/naming"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type analysis struct {
|
||||
@@ -15,12 +16,11 @@ type analysis struct {
|
||||
}
|
||||
|
||||
type dependency struct {
|
||||
Identifiers []identifier `xml:"identifiers>identifier"`
|
||||
Identifiers []vulnerabilityID `xml:"identifiers>vulnerabilityIds"`
|
||||
}
|
||||
|
||||
type identifier struct {
|
||||
Name string `xml:"name"`
|
||||
Type string `xml:"type,attr"`
|
||||
type vulnerabilityID struct {
|
||||
ID string `xml:"id"`
|
||||
}
|
||||
|
||||
func appendIfMissing(slice []string, str string) []string {
|
||||
@@ -49,17 +49,22 @@ func Parse(path string) ([]string, error) {
|
||||
|
||||
var anal analysis
|
||||
if err := xml.Unmarshal(b, &anal); err != nil {
|
||||
return nil, fmt.Errorf("Failed to unmarshal: %s", err)
|
||||
return nil, xerrors.Errorf("Failed to unmarshal: %s", err)
|
||||
}
|
||||
|
||||
cpes := []string{}
|
||||
for _, d := range anal.Dependencies {
|
||||
for _, ident := range d.Identifiers {
|
||||
if ident.Type == "cpe" {
|
||||
name := strings.TrimPrefix(ident.Name, "(")
|
||||
name = strings.TrimSuffix(name, ")")
|
||||
cpes = appendIfMissing(cpes, name)
|
||||
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
|
||||
|
||||
35
contrib/trivy/README.md
Normal file
35
contrib/trivy/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# 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
|
||||
```
|
||||
78
contrib/trivy/cmd/main.go
Normal file
78
contrib/trivy/cmd/main.go
Normal file
@@ -0,0 +1,78 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
213
contrib/trivy/parser/parser.go
Normal file
213
contrib/trivy/parser/parser.go
Normal file
@@ -0,0 +1,213 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer/os"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/future-architect/vuls/constant"
|
||||
"github.com/future-architect/vuls/models"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
setScanResultMeta(scanResult, &trivyResult)
|
||||
for _, vuln := range trivyResult.Vulnerabilities {
|
||||
if _, ok := vulnInfos[vuln.VulnerabilityID]; !ok {
|
||||
vulnInfos[vuln.VulnerabilityID] = models.VulnInfo{
|
||||
CveID: vuln.VulnerabilityID,
|
||||
Confidences: models.Confidences{
|
||||
{
|
||||
Score: 100,
|
||||
DetectionMethod: models.TrivyMatchStr,
|
||||
},
|
||||
},
|
||||
AffectedPackages: models.PackageFixStatuses{},
|
||||
CveContents: models.CveContents{},
|
||||
LibraryFixedIns: models.LibraryFixedIns{},
|
||||
// VulnType : "",
|
||||
}
|
||||
}
|
||||
vulnInfo := vulnInfos[vuln.VulnerabilityID]
|
||||
var notFixedYet bool
|
||||
fixState := ""
|
||||
if len(vuln.FixedVersion) == 0 {
|
||||
notFixedYet = true
|
||||
fixState = "Affected"
|
||||
}
|
||||
var references models.References
|
||||
for _, reference := range vuln.References {
|
||||
references = append(references, models.Reference{
|
||||
Source: "trivy",
|
||||
Link: reference,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Slice(references, func(i, j int) bool {
|
||||
return references[i].Link < references[j].Link
|
||||
})
|
||||
|
||||
var published time.Time
|
||||
if vuln.PublishedDate != nil {
|
||||
published = *vuln.PublishedDate
|
||||
}
|
||||
|
||||
var lastModified time.Time
|
||||
if vuln.LastModifiedDate != nil {
|
||||
lastModified = *vuln.LastModifiedDate
|
||||
}
|
||||
|
||||
vulnInfo.CveContents = models.CveContents{
|
||||
models.Trivy: []models.CveContent{{
|
||||
Cvss3Severity: vuln.Severity,
|
||||
References: references,
|
||||
Title: vuln.Title,
|
||||
Summary: vuln.Description,
|
||||
Published: published,
|
||||
LastModified: lastModified,
|
||||
}},
|
||||
}
|
||||
// do only if image type is Vuln
|
||||
if isTrivySupportedOS(trivyResult.Type) {
|
||||
pkgs[vuln.PkgName] = models.Package{
|
||||
Name: vuln.PkgName,
|
||||
Version: vuln.InstalledVersion,
|
||||
}
|
||||
vulnInfo.AffectedPackages = append(vulnInfo.AffectedPackages, models.PackageFixStatus{
|
||||
Name: vuln.PkgName,
|
||||
NotFixedYet: notFixedYet,
|
||||
FixState: fixState,
|
||||
FixedIn: vuln.FixedVersion,
|
||||
})
|
||||
} else {
|
||||
vulnInfo.LibraryFixedIns = append(vulnInfo.LibraryFixedIns, models.LibraryFixedIn{
|
||||
Key: trivyResult.Type,
|
||||
Name: vuln.PkgName,
|
||||
Path: trivyResult.Target,
|
||||
FixedIn: vuln.FixedVersion,
|
||||
})
|
||||
libScanner := uniqueLibraryScannerPaths[trivyResult.Target]
|
||||
libScanner.Type = trivyResult.Type
|
||||
libScanner.Libs = append(libScanner.Libs, 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{
|
||||
Type: v.Type,
|
||||
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
|
||||
}
|
||||
|
||||
const trivyTarget = "trivy-target"
|
||||
|
||||
func setScanResultMeta(scanResult *models.ScanResult, trivyResult *report.Result) {
|
||||
if isTrivySupportedOS(trivyResult.Type) {
|
||||
scanResult.Family = trivyResult.Type
|
||||
scanResult.ServerName = trivyResult.Target
|
||||
scanResult.Optional = map[string]interface{}{
|
||||
trivyTarget: trivyResult.Target,
|
||||
}
|
||||
} else if isTrivySupportedLib(trivyResult.Type) {
|
||||
if scanResult.Family == "" {
|
||||
scanResult.Family = constant.ServerTypePseudo
|
||||
}
|
||||
if scanResult.ServerName == "" {
|
||||
scanResult.ServerName = "library scan by trivy"
|
||||
}
|
||||
if _, ok := scanResult.Optional[trivyTarget]; !ok {
|
||||
scanResult.Optional = map[string]interface{}{
|
||||
trivyTarget: trivyResult.Target,
|
||||
}
|
||||
}
|
||||
}
|
||||
scanResult.ScannedAt = time.Now()
|
||||
scanResult.ScannedBy = "trivy"
|
||||
scanResult.ScannedVia = "trivy"
|
||||
}
|
||||
|
||||
// isTrivySupportedOS :
|
||||
func isTrivySupportedOS(family string) bool {
|
||||
supportedFamilies := map[string]interface{}{
|
||||
os.RedHat: struct{}{},
|
||||
os.Debian: struct{}{},
|
||||
os.Ubuntu: struct{}{},
|
||||
os.CentOS: struct{}{},
|
||||
os.Fedora: struct{}{},
|
||||
os.Amazon: struct{}{},
|
||||
os.Oracle: struct{}{},
|
||||
os.Windows: struct{}{},
|
||||
os.OpenSUSE: struct{}{},
|
||||
os.OpenSUSELeap: struct{}{},
|
||||
os.OpenSUSETumbleweed: struct{}{},
|
||||
os.SLES: struct{}{},
|
||||
os.Photon: struct{}{},
|
||||
os.Alpine: struct{}{},
|
||||
}
|
||||
_, ok := supportedFamilies[family]
|
||||
return ok
|
||||
}
|
||||
|
||||
func isTrivySupportedLib(typestr string) bool {
|
||||
supportedLibs := map[string]interface{}{
|
||||
ftypes.Bundler: struct{}{},
|
||||
ftypes.Cargo: struct{}{},
|
||||
ftypes.Composer: struct{}{},
|
||||
ftypes.Npm: struct{}{},
|
||||
ftypes.NuGet: struct{}{},
|
||||
ftypes.Pip: struct{}{},
|
||||
ftypes.Pipenv: struct{}{},
|
||||
ftypes.Poetry: struct{}{},
|
||||
ftypes.Yarn: struct{}{},
|
||||
ftypes.Jar: struct{}{},
|
||||
ftypes.GoBinary: struct{}{},
|
||||
ftypes.GoMod: struct{}{},
|
||||
}
|
||||
_, ok := supportedLibs[typestr]
|
||||
return ok
|
||||
}
|
||||
5611
contrib/trivy/parser/parser_test.go
Normal file
5611
contrib/trivy/parser/parser_test.go
Normal file
File diff suppressed because it is too large
Load Diff
33
cwe/cwe.go
Normal file
33
cwe/cwe.go
Normal file
@@ -0,0 +1,33 @@
|
||||
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"
|
||||
33
cwe/sans.go
Normal file
33
cwe/sans.go
Normal file
@@ -0,0 +1,33 @@
|
||||
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/"
|
||||
228
detector/cve_client.go
Normal file
228
detector/cve_client.go
Normal file
@@ -0,0 +1,228 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package detector
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/util"
|
||||
cvedb "github.com/vulsio/go-cve-dictionary/db"
|
||||
cvelog "github.com/vulsio/go-cve-dictionary/log"
|
||||
cvemodels "github.com/vulsio/go-cve-dictionary/models"
|
||||
)
|
||||
|
||||
type goCveDictClient struct {
|
||||
cnf config.VulnDictInterface
|
||||
driver cvedb.DB
|
||||
}
|
||||
|
||||
func newGoCveDictClient(cnf config.VulnDictInterface, o logging.LogOpts) (*goCveDictClient, error) {
|
||||
if err := cvelog.SetLogger(o.LogToFile, o.LogDir, o.Debug, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
driver, locked, err := newCveDB(cnf)
|
||||
if locked {
|
||||
return nil, xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &goCveDictClient{cnf: cnf, driver: driver}, nil
|
||||
}
|
||||
|
||||
func (api goCveDictClient) closeDB() error {
|
||||
if api.driver == nil {
|
||||
return nil
|
||||
}
|
||||
if err := api.driver.CloseDB(); err != nil {
|
||||
return xerrors.Errorf("Failed to close DB: %+v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (api goCveDictClient) fetchCveDetails(cveIDs []string) (cveDetails []cvemodels.CveDetail, err error) {
|
||||
for _, cveID := range cveIDs {
|
||||
cveDetail, err := api.driver.Get(cveID)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to fetch CVE. err: %w", err)
|
||||
}
|
||||
cveDetails = append(cveDetails, *cveDetail)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type response struct {
|
||||
Key string
|
||||
CveDetail cvemodels.CveDetail
|
||||
}
|
||||
|
||||
func (api goCveDictClient) fetchCveDetailsViaHTTP(cveIDs []string) (cveDetails []cvemodels.CveDetail, err error) {
|
||||
reqChan := make(chan string, len(cveIDs))
|
||||
resChan := make(chan response, len(cveIDs))
|
||||
errChan := make(chan error, len(cveIDs))
|
||||
defer close(reqChan)
|
||||
defer close(resChan)
|
||||
defer close(errChan)
|
||||
|
||||
go func() {
|
||||
for _, cveID := range cveIDs {
|
||||
reqChan <- cveID
|
||||
}
|
||||
}()
|
||||
|
||||
concurrency := 10
|
||||
tasks := util.GenWorkers(concurrency)
|
||||
for range cveIDs {
|
||||
tasks <- func() {
|
||||
select {
|
||||
case cveID := <-reqChan:
|
||||
url, err := util.URLPathJoin(api.cnf.GetURL(), "cves", cveID)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
} else {
|
||||
logging.Log.Debugf("HTTP Request to %s", url)
|
||||
api.httpGet(cveID, url, resChan, errChan)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timeout := time.After(2 * 60 * time.Second)
|
||||
var errs []error
|
||||
for range cveIDs {
|
||||
select {
|
||||
case res := <-resChan:
|
||||
cveDetails = append(cveDetails, res.CveDetail)
|
||||
case err := <-errChan:
|
||||
errs = append(errs, err)
|
||||
case <-timeout:
|
||||
return nil, xerrors.New("Timeout Fetching CVE")
|
||||
}
|
||||
}
|
||||
if len(errs) != 0 {
|
||||
return nil,
|
||||
xerrors.Errorf("Failed to fetch CVE. err: %w", errs)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (api goCveDictClient) httpGet(key, url string, resChan chan<- response, errChan chan<- error) {
|
||||
var body string
|
||||
var errs []error
|
||||
var resp *http.Response
|
||||
f := func() (err error) {
|
||||
resp, body, errs = gorequest.New().Timeout(10 * time.Second).Get(url).End()
|
||||
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
|
||||
return xerrors.Errorf("HTTP GET Error, url: %s, resp: %v, err: %+v",
|
||||
url, resp, errs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
notify := func(err error, t time.Duration) {
|
||||
logging.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %+v", t, err)
|
||||
}
|
||||
err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify)
|
||||
if err != nil {
|
||||
errChan <- xerrors.Errorf("HTTP Error: %w", err)
|
||||
return
|
||||
}
|
||||
cveDetail := cvemodels.CveDetail{}
|
||||
if err := json.Unmarshal([]byte(body), &cveDetail); err != nil {
|
||||
errChan <- xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
|
||||
return
|
||||
}
|
||||
resChan <- response{
|
||||
key,
|
||||
cveDetail,
|
||||
}
|
||||
}
|
||||
|
||||
func (api goCveDictClient) detectCveByCpeURI(cpeURI string, useJVN bool) (cves []cvemodels.CveDetail, err error) {
|
||||
if api.cnf.IsFetchViaHTTP() {
|
||||
url, err := util.URLPathJoin(api.cnf.GetURL(), "cpes")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := map[string]string{"name": cpeURI}
|
||||
logging.Log.Debugf("HTTP Request to %s, query: %#v", url, query)
|
||||
if cves, err = api.httpPost(url, query); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if cves, err = api.driver.GetByCpeURI(cpeURI); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if useJVN {
|
||||
return cves, nil
|
||||
}
|
||||
|
||||
nvdCves := []cvemodels.CveDetail{}
|
||||
for _, cve := range cves {
|
||||
if !cve.HasNvd() {
|
||||
continue
|
||||
}
|
||||
cve.Jvns = []cvemodels.Jvn{}
|
||||
nvdCves = append(nvdCves, cve)
|
||||
}
|
||||
return nvdCves, nil
|
||||
}
|
||||
|
||||
func (api goCveDictClient) httpPost(url string, query map[string]string) ([]cvemodels.CveDetail, error) {
|
||||
var body string
|
||||
var errs []error
|
||||
var resp *http.Response
|
||||
f := func() (err error) {
|
||||
req := gorequest.New().Timeout(10 * time.Second).Post(url)
|
||||
for key := range query {
|
||||
req = req.Send(fmt.Sprintf("%s=%s", key, query[key])).Type("json")
|
||||
}
|
||||
resp, body, errs = req.End()
|
||||
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
|
||||
return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %+v", url, resp, errs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
notify := func(err error, t time.Duration) {
|
||||
logging.Log.Warnf("Failed to HTTP POST. retrying in %s seconds. err: %+v", t, err)
|
||||
}
|
||||
err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("HTTP Error: %w", err)
|
||||
}
|
||||
|
||||
cveDetails := []cvemodels.CveDetail{}
|
||||
if err := json.Unmarshal([]byte(body), &cveDetails); err != nil {
|
||||
return nil,
|
||||
xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
|
||||
}
|
||||
return cveDetails, nil
|
||||
}
|
||||
|
||||
func newCveDB(cnf config.VulnDictInterface) (driver cvedb.DB, locked bool, err error) {
|
||||
if cnf.IsFetchViaHTTP() {
|
||||
return nil, false, nil
|
||||
}
|
||||
path := cnf.GetURL()
|
||||
if cnf.GetType() == "sqlite3" {
|
||||
path = cnf.GetSQLite3Path()
|
||||
}
|
||||
driver, locked, err = cvedb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL())
|
||||
if err != nil {
|
||||
err = xerrors.Errorf("Failed to init CVE DB. err: %w, path: %s", err, path)
|
||||
return nil, locked, err
|
||||
}
|
||||
return driver, false, nil
|
||||
}
|
||||
563
detector/detector.go
Normal file
563
detector/detector.go
Normal file
@@ -0,0 +1,563 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package detector
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/constant"
|
||||
"github.com/future-architect/vuls/contrib/owasp-dependency-check/parser"
|
||||
"github.com/future-architect/vuls/cwe"
|
||||
"github.com/future-architect/vuls/gost"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/oval"
|
||||
"github.com/future-architect/vuls/reporter"
|
||||
"github.com/future-architect/vuls/util"
|
||||
cvemodels "github.com/vulsio/go-cve-dictionary/models"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// Cpe :
|
||||
type Cpe struct {
|
||||
CpeURI string
|
||||
UseJVN bool
|
||||
}
|
||||
|
||||
// Detect vulns and fill CVE detailed information
|
||||
func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
|
||||
|
||||
// Use the same reportedAt for all rs
|
||||
reportedAt := time.Now()
|
||||
for i, r := range rs {
|
||||
if !config.Conf.RefreshCve && !needToRefreshCve(r) {
|
||||
logging.Log.Info("No need to refresh")
|
||||
continue
|
||||
}
|
||||
|
||||
if !reuseScannedCves(&r) {
|
||||
r.ScannedCves = models.VulnInfos{}
|
||||
}
|
||||
|
||||
if err := DetectLibsCves(&r, config.Conf.TrivyCacheDBDir, config.Conf.NoProgress); err != nil {
|
||||
return nil, xerrors.Errorf("Failed to fill with Library dependency: %w", err)
|
||||
}
|
||||
|
||||
if err := DetectPkgCves(&r, config.Conf.OvalDict, config.Conf.Gost); err != nil {
|
||||
return nil, xerrors.Errorf("Failed to detect Pkg CVE: %w", err)
|
||||
}
|
||||
|
||||
cpeURIs, owaspDCXMLPath := []string{}, ""
|
||||
cpes := []Cpe{}
|
||||
if len(r.Container.ContainerID) == 0 {
|
||||
cpeURIs = config.Conf.Servers[r.ServerName].CpeNames
|
||||
owaspDCXMLPath = config.Conf.Servers[r.ServerName].OwaspDCXMLPath
|
||||
} else {
|
||||
if s, ok := config.Conf.Servers[r.ServerName]; ok {
|
||||
if con, ok := s.Containers[r.Container.Name]; ok {
|
||||
cpeURIs = con.Cpes
|
||||
owaspDCXMLPath = con.OwaspDCXMLPath
|
||||
}
|
||||
}
|
||||
}
|
||||
if owaspDCXMLPath != "" {
|
||||
cpes, err := parser.Parse(owaspDCXMLPath)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to read OWASP Dependency Check XML on %s, `%s`, err: %w",
|
||||
r.ServerInfo(), owaspDCXMLPath, err)
|
||||
}
|
||||
cpeURIs = append(cpeURIs, cpes...)
|
||||
}
|
||||
for _, uri := range cpeURIs {
|
||||
cpes = append(cpes, Cpe{
|
||||
CpeURI: uri,
|
||||
UseJVN: true,
|
||||
})
|
||||
}
|
||||
if err := DetectCpeURIsCves(&r, cpes, config.Conf.CveDict, config.Conf.LogOpts); err != nil {
|
||||
return nil, xerrors.Errorf("Failed to detect CVE of `%s`: %w", cpeURIs, err)
|
||||
}
|
||||
|
||||
repos := config.Conf.Servers[r.ServerName].GitHubRepos
|
||||
if err := DetectGitHubCves(&r, repos); err != nil {
|
||||
return nil, xerrors.Errorf("Failed to detect GitHub Cves: %w", err)
|
||||
}
|
||||
|
||||
if err := DetectWordPressCves(&r, config.Conf.WpScan); err != nil {
|
||||
return nil, xerrors.Errorf("Failed to detect WordPress Cves: %w", err)
|
||||
}
|
||||
|
||||
if err := gost.FillCVEsWithRedHat(&r, config.Conf.Gost); err != nil {
|
||||
return nil, xerrors.Errorf("Failed to fill with gost: %w", err)
|
||||
}
|
||||
|
||||
if err := FillCvesWithNvdJvn(&r, config.Conf.CveDict, config.Conf.LogOpts); err != nil {
|
||||
return nil, xerrors.Errorf("Failed to fill with CVE: %w", err)
|
||||
}
|
||||
|
||||
nExploitCve, err := FillWithExploit(&r, config.Conf.Exploit)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to fill with exploit: %w", err)
|
||||
}
|
||||
logging.Log.Infof("%s: %d PoC are detected", r.FormatServerName(), nExploitCve)
|
||||
|
||||
nMetasploitCve, err := FillWithMetasploit(&r, config.Conf.Metasploit)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to fill with metasploit: %w", err)
|
||||
}
|
||||
logging.Log.Infof("%s: %d exploits are detected", r.FormatServerName(), nMetasploitCve)
|
||||
|
||||
FillCweDict(&r)
|
||||
|
||||
r.ReportedBy, _ = os.Hostname()
|
||||
r.Lang = config.Conf.Lang
|
||||
r.ReportedAt = reportedAt
|
||||
r.ReportedVersion = config.Version
|
||||
r.ReportedRevision = config.Revision
|
||||
r.Config.Report = config.Conf
|
||||
r.Config.Report.Servers = map[string]config.ServerInfo{
|
||||
r.ServerName: config.Conf.Servers[r.ServerName],
|
||||
}
|
||||
rs[i] = r
|
||||
}
|
||||
|
||||
// Overwrite the json file every time to clear the fields specified in config.IgnoredJSONKeys
|
||||
for _, r := range rs {
|
||||
if s, ok := config.Conf.Servers[r.ServerName]; ok {
|
||||
r = r.ClearFields(s.IgnoredJSONKeys)
|
||||
}
|
||||
//TODO don't call here
|
||||
if err := reporter.OverwriteJSONFile(dir, r); err != nil {
|
||||
return nil, xerrors.Errorf("Failed to write JSON: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if config.Conf.DiffPlus || config.Conf.DiffMinus {
|
||||
prevs, err := loadPrevious(rs, config.Conf.ResultsDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rs = diff(rs, prevs, config.Conf.DiffPlus, config.Conf.DiffMinus)
|
||||
}
|
||||
|
||||
for i, r := range rs {
|
||||
r.ScannedCves = r.ScannedCves.FilterByCvssOver(config.Conf.CvssScoreOver)
|
||||
r.ScannedCves = r.ScannedCves.FilterUnfixed(config.Conf.IgnoreUnfixed)
|
||||
r.ScannedCves = r.ScannedCves.FilterByConfidenceOver(config.Conf.ConfidenceScoreOver)
|
||||
|
||||
// IgnoreCves
|
||||
ignoreCves := []string{}
|
||||
if r.Container.Name == "" {
|
||||
ignoreCves = config.Conf.Servers[r.ServerName].IgnoreCves
|
||||
} else if con, ok := config.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {
|
||||
ignoreCves = con.IgnoreCves
|
||||
}
|
||||
r.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)
|
||||
|
||||
// ignorePkgs
|
||||
ignorePkgsRegexps := []string{}
|
||||
if r.Container.Name == "" {
|
||||
ignorePkgsRegexps = config.Conf.Servers[r.ServerName].IgnorePkgsRegexp
|
||||
} else if s, ok := config.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {
|
||||
ignorePkgsRegexps = s.IgnorePkgsRegexp
|
||||
}
|
||||
r.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)
|
||||
|
||||
// IgnoreUnscored
|
||||
if config.Conf.IgnoreUnscoredCves {
|
||||
r.ScannedCves = r.ScannedCves.FindScoredVulns()
|
||||
}
|
||||
|
||||
r.FilterInactiveWordPressLibs(config.Conf.WpScan.DetectInactive)
|
||||
rs[i] = r
|
||||
}
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
// DetectPkgCves detects OS pkg cves
|
||||
// pass 2 configs
|
||||
func DetectPkgCves(r *models.ScanResult, ovalCnf config.GovalDictConf, gostCnf config.GostConf) error {
|
||||
// Pkg Scan
|
||||
if r.Release != "" {
|
||||
// OVAL, gost(Debian Security Tracker) does not support Package for Raspbian, so skip it.
|
||||
if r.Family == constant.Raspbian {
|
||||
r = r.RemoveRaspbianPackFromResult()
|
||||
}
|
||||
|
||||
// OVAL
|
||||
if err := detectPkgsCvesWithOval(ovalCnf, r); err != nil {
|
||||
return xerrors.Errorf("Failed to detect CVE with OVAL: %w", err)
|
||||
}
|
||||
|
||||
// gost
|
||||
if err := detectPkgsCvesWithGost(gostCnf, r); err != nil {
|
||||
return xerrors.Errorf("Failed to detect CVE with gost: %w", err)
|
||||
}
|
||||
} else if reuseScannedCves(r) {
|
||||
logging.Log.Infof("r.Release is empty. Use CVEs as it as.")
|
||||
} else if r.Family == constant.ServerTypePseudo {
|
||||
logging.Log.Infof("pseudo type. Skip OVAL and gost detection")
|
||||
} else {
|
||||
logging.Log.Infof("r.Release is empty. detect as pseudo type. Skip OVAL and gost detection")
|
||||
}
|
||||
|
||||
for i, v := range r.ScannedCves {
|
||||
for j, p := range v.AffectedPackages {
|
||||
if p.NotFixedYet && p.FixState == "" {
|
||||
p.FixState = "Not fixed yet"
|
||||
r.ScannedCves[i].AffectedPackages[j] = p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// To keep backward compatibility
|
||||
// Newer versions use ListenPortStats,
|
||||
// but older versions of Vuls are set to ListenPorts.
|
||||
// Set ListenPorts to ListenPortStats to allow newer Vuls to report old results.
|
||||
for i, pkg := range r.Packages {
|
||||
for j, proc := range pkg.AffectedProcs {
|
||||
for _, ipPort := range proc.ListenPorts {
|
||||
ps, err := models.NewPortStat(ipPort)
|
||||
if err != nil {
|
||||
logging.Log.Warnf("Failed to parse ip:port: %s, err:%+v", ipPort, err)
|
||||
continue
|
||||
}
|
||||
r.Packages[i].AffectedProcs[j].ListenPortStats = append(
|
||||
r.Packages[i].AffectedProcs[j].ListenPortStats, *ps)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DetectGitHubCves fetches CVEs from GitHub Security Alerts
|
||||
func DetectGitHubCves(r *models.ScanResult, githubConfs map[string]config.GitHubConf) error {
|
||||
if len(githubConfs) == 0 {
|
||||
return nil
|
||||
}
|
||||
for ownerRepo, setting := range githubConfs {
|
||||
ss := strings.Split(ownerRepo, "/")
|
||||
if len(ss) != 2 {
|
||||
return xerrors.Errorf("Failed to parse GitHub owner/repo: %s", ownerRepo)
|
||||
}
|
||||
owner, repo := ss[0], ss[1]
|
||||
n, err := DetectGitHubSecurityAlerts(r, owner, repo, setting.Token, setting.IgnoreGitHubDismissed)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("Failed to access GitHub Security Alerts: %w", err)
|
||||
}
|
||||
logging.Log.Infof("%s: %d CVEs detected with GHSA %s/%s",
|
||||
r.FormatServerName(), n, owner, repo)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DetectWordPressCves detects CVEs of WordPress
|
||||
func DetectWordPressCves(r *models.ScanResult, wpCnf config.WpScanConf) error {
|
||||
if len(r.WordPressPackages) == 0 {
|
||||
return nil
|
||||
}
|
||||
logging.Log.Infof("%s: Detect WordPress CVE. Number of pkgs: %d ", r.ServerInfo(), len(r.WordPressPackages))
|
||||
n, err := detectWordPressCves(r, wpCnf)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("Failed to detect WordPress CVE: %w", err)
|
||||
}
|
||||
logging.Log.Infof("%s: found %d WordPress CVEs", r.FormatServerName(), n)
|
||||
return nil
|
||||
}
|
||||
|
||||
// FillCvesWithNvdJvn fills CVE detail with NVD, JVN
|
||||
func FillCvesWithNvdJvn(r *models.ScanResult, cnf config.GoCveDictConf, logOpts logging.LogOpts) (err error) {
|
||||
cveIDs := []string{}
|
||||
for _, v := range r.ScannedCves {
|
||||
cveIDs = append(cveIDs, v.CveID)
|
||||
}
|
||||
|
||||
client, err := newGoCveDictClient(&cnf, logOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := client.closeDB(); err != nil {
|
||||
logging.Log.Errorf("Failed to close DB. err: %+v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var ds []cvemodels.CveDetail
|
||||
if cnf.IsFetchViaHTTP() {
|
||||
ds, err = client.fetchCveDetailsViaHTTP(cveIDs)
|
||||
} else {
|
||||
ds, err = client.fetchCveDetails(cveIDs)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, d := range ds {
|
||||
nvds, exploits, mitigations := models.ConvertNvdToModel(d.CveID, d.Nvds)
|
||||
jvns := models.ConvertJvnToModel(d.CveID, d.Jvns)
|
||||
|
||||
alerts := fillCertAlerts(&d)
|
||||
for cveID, vinfo := range r.ScannedCves {
|
||||
if vinfo.CveID == d.CveID {
|
||||
if vinfo.CveContents == nil {
|
||||
vinfo.CveContents = models.CveContents{}
|
||||
}
|
||||
for _, con := range nvds {
|
||||
if !con.Empty() {
|
||||
vinfo.CveContents[con.Type] = []models.CveContent{con}
|
||||
}
|
||||
}
|
||||
for _, con := range jvns {
|
||||
if !con.Empty() {
|
||||
found := false
|
||||
for _, cveCont := range vinfo.CveContents[con.Type] {
|
||||
if con.SourceLink == cveCont.SourceLink {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
vinfo.CveContents[con.Type] = append(vinfo.CveContents[con.Type], con)
|
||||
}
|
||||
}
|
||||
}
|
||||
vinfo.AlertDict = alerts
|
||||
vinfo.Exploits = append(vinfo.Exploits, exploits...)
|
||||
vinfo.Mitigations = append(vinfo.Mitigations, mitigations...)
|
||||
r.ScannedCves[cveID] = vinfo
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fillCertAlerts(cvedetail *cvemodels.CveDetail) (dict models.AlertDict) {
|
||||
for _, nvd := range cvedetail.Nvds {
|
||||
for _, cert := range nvd.Certs {
|
||||
dict.En = append(dict.En, models.Alert{
|
||||
URL: cert.Link,
|
||||
Title: cert.Title,
|
||||
Team: "us",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for _, jvn := range cvedetail.Jvns {
|
||||
for _, cert := range jvn.Certs {
|
||||
dict.Ja = append(dict.Ja, models.Alert{
|
||||
URL: cert.Link,
|
||||
Title: cert.Title,
|
||||
Team: "jp",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return dict
|
||||
}
|
||||
|
||||
// detectPkgsCvesWithOval fetches OVAL database
|
||||
func detectPkgsCvesWithOval(cnf config.GovalDictConf, r *models.ScanResult) error {
|
||||
ovalClient, err := oval.NewOVALClient(r.Family, cnf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ovalClient == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
logging.Log.Debugf("Check if oval fetched: %s %s", r.Family, r.Release)
|
||||
ok, err := ovalClient.CheckIfOvalFetched(r.Family, r.Release)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
if r.Family == constant.Debian {
|
||||
logging.Log.Infof("Skip OVAL and Scan with gost alone.")
|
||||
logging.Log.Infof("%s: %d CVEs are detected with OVAL", r.FormatServerName(), 0)
|
||||
return nil
|
||||
}
|
||||
return xerrors.Errorf("OVAL entries of %s %s are not found. Fetch OVAL before reporting. For details, see `https://github.com/vulsio/goval-dictionary#usage`", r.Family, r.Release)
|
||||
}
|
||||
|
||||
logging.Log.Debugf("Check if oval fresh: %s %s", r.Family, r.Release)
|
||||
_, err = ovalClient.CheckIfOvalFresh(r.Family, r.Release)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logging.Log.Debugf("Fill with oval: %s %s", r.Family, r.Release)
|
||||
nCVEs, err := ovalClient.FillWithOval(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logging.Log.Infof("%s: %d CVEs are detected with OVAL", r.FormatServerName(), nCVEs)
|
||||
return nil
|
||||
}
|
||||
|
||||
func detectPkgsCvesWithGost(cnf config.GostConf, r *models.ScanResult) error {
|
||||
client, err := gost.NewClient(cnf, r.Family)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("Failed to new a gost client: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := client.CloseDB(); err != nil {
|
||||
logging.Log.Errorf("Failed to close the gost DB. err: %+v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
nCVEs, err := client.DetectCVEs(r, true)
|
||||
if err != nil {
|
||||
if r.Family == constant.Debian {
|
||||
return xerrors.Errorf("Failed to detect CVEs with gost: %w", err)
|
||||
}
|
||||
return xerrors.Errorf("Failed to detect unfixed CVEs with gost: %w", err)
|
||||
}
|
||||
|
||||
if r.Family == constant.Debian {
|
||||
logging.Log.Infof("%s: %d CVEs are detected with gost",
|
||||
r.FormatServerName(), nCVEs)
|
||||
} else {
|
||||
logging.Log.Infof("%s: %d unfixed CVEs are detected with gost",
|
||||
r.FormatServerName(), nCVEs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DetectCpeURIsCves detects CVEs of given CPE-URIs
|
||||
func DetectCpeURIsCves(r *models.ScanResult, cpes []Cpe, cnf config.GoCveDictConf, logOpts logging.LogOpts) error {
|
||||
client, err := newGoCveDictClient(&cnf, logOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := client.closeDB(); err != nil {
|
||||
logging.Log.Errorf("Failed to close DB. err: %+v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
nCVEs := 0
|
||||
for _, cpe := range cpes {
|
||||
details, err := client.detectCveByCpeURI(cpe.CpeURI, cpe.UseJVN)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, detail := range details {
|
||||
advisories := []models.DistroAdvisory{}
|
||||
if !detail.HasNvd() && detail.HasJvn() {
|
||||
for _, jvn := range detail.Jvns {
|
||||
advisories = append(advisories, models.DistroAdvisory{
|
||||
AdvisoryID: jvn.JvnID,
|
||||
})
|
||||
}
|
||||
}
|
||||
maxConfidence := getMaxConfidence(detail)
|
||||
|
||||
if val, ok := r.ScannedCves[detail.CveID]; ok {
|
||||
val.CpeURIs = util.AppendIfMissing(val.CpeURIs, cpe.CpeURI)
|
||||
val.Confidences.AppendIfMissing(maxConfidence)
|
||||
val.DistroAdvisories = advisories
|
||||
r.ScannedCves[detail.CveID] = val
|
||||
} else {
|
||||
v := models.VulnInfo{
|
||||
CveID: detail.CveID,
|
||||
CpeURIs: []string{cpe.CpeURI},
|
||||
Confidences: models.Confidences{maxConfidence},
|
||||
DistroAdvisories: advisories,
|
||||
}
|
||||
r.ScannedCves[detail.CveID] = v
|
||||
nCVEs++
|
||||
}
|
||||
}
|
||||
}
|
||||
logging.Log.Infof("%s: %d CVEs are detected with CPE", r.FormatServerName(), nCVEs)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getMaxConfidence(detail cvemodels.CveDetail) (max models.Confidence) {
|
||||
if !detail.HasNvd() && detail.HasJvn() {
|
||||
return models.JvnVendorProductMatch
|
||||
} else if detail.HasNvd() {
|
||||
for _, nvd := range detail.Nvds {
|
||||
confidence := models.Confidence{}
|
||||
switch nvd.DetectionMethod {
|
||||
case cvemodels.NvdExactVersionMatch:
|
||||
confidence = models.NvdExactVersionMatch
|
||||
case cvemodels.NvdRoughVersionMatch:
|
||||
confidence = models.NvdRoughVersionMatch
|
||||
case cvemodels.NvdVendorProductMatch:
|
||||
confidence = models.NvdVendorProductMatch
|
||||
}
|
||||
if max.Score < confidence.Score {
|
||||
max = confidence
|
||||
}
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
// FillCweDict fills CWE
|
||||
func FillCweDict(r *models.ScanResult) {
|
||||
uniqCweIDMap := map[string]bool{}
|
||||
for _, vinfo := range r.ScannedCves {
|
||||
for _, conts := range vinfo.CveContents {
|
||||
for _, cont := range conts {
|
||||
for _, id := range cont.CweIDs {
|
||||
if strings.HasPrefix(id, "CWE-") {
|
||||
id = strings.TrimPrefix(id, "CWE-")
|
||||
uniqCweIDMap[id] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dict := map[string]models.CweDictEntry{}
|
||||
for id := range uniqCweIDMap {
|
||||
entry := models.CweDictEntry{}
|
||||
if e, ok := cwe.CweDictEn[id]; ok {
|
||||
if rank, ok := cwe.OwaspTopTen2017[id]; ok {
|
||||
entry.OwaspTopTen2017 = rank
|
||||
}
|
||||
if rank, ok := cwe.CweTopTwentyfive2019[id]; ok {
|
||||
entry.CweTopTwentyfive2019 = rank
|
||||
}
|
||||
if rank, ok := cwe.SansTopTwentyfive[id]; ok {
|
||||
entry.SansTopTwentyfive = rank
|
||||
}
|
||||
entry.En = &e
|
||||
} else {
|
||||
logging.Log.Debugf("CWE-ID %s is not found in English CWE Dict", id)
|
||||
entry.En = &cwe.Cwe{CweID: id}
|
||||
}
|
||||
|
||||
if r.Lang == "ja" {
|
||||
if e, ok := cwe.CweDictJa[id]; ok {
|
||||
if rank, ok := cwe.OwaspTopTen2017[id]; ok {
|
||||
entry.OwaspTopTen2017 = rank
|
||||
}
|
||||
if rank, ok := cwe.CweTopTwentyfive2019[id]; ok {
|
||||
entry.CweTopTwentyfive2019 = rank
|
||||
}
|
||||
if rank, ok := cwe.SansTopTwentyfive[id]; ok {
|
||||
entry.SansTopTwentyfive = rank
|
||||
}
|
||||
entry.Ja = &e
|
||||
} else {
|
||||
logging.Log.Debugf("CWE-ID %s is not found in Japanese CWE Dict", id)
|
||||
entry.Ja = &cwe.Cwe{CweID: id}
|
||||
}
|
||||
}
|
||||
dict[id] = entry
|
||||
}
|
||||
r.CweDict = dict
|
||||
return
|
||||
}
|
||||
90
detector/detector_test.go
Normal file
90
detector/detector_test.go
Normal file
@@ -0,0 +1,90 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package detector
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/future-architect/vuls/models"
|
||||
cvemodels "github.com/vulsio/go-cve-dictionary/models"
|
||||
)
|
||||
|
||||
func Test_getMaxConfidence(t *testing.T) {
|
||||
type args struct {
|
||||
detail cvemodels.CveDetail
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantMax models.Confidence
|
||||
}{
|
||||
{
|
||||
name: "JvnVendorProductMatch",
|
||||
args: args{
|
||||
detail: cvemodels.CveDetail{
|
||||
Nvds: []cvemodels.Nvd{},
|
||||
Jvns: []cvemodels.Jvn{{}},
|
||||
},
|
||||
},
|
||||
wantMax: models.JvnVendorProductMatch,
|
||||
},
|
||||
{
|
||||
name: "NvdExactVersionMatch",
|
||||
args: args{
|
||||
detail: cvemodels.CveDetail{
|
||||
Nvds: []cvemodels.Nvd{
|
||||
{DetectionMethod: cvemodels.NvdRoughVersionMatch},
|
||||
{DetectionMethod: cvemodels.NvdVendorProductMatch},
|
||||
{DetectionMethod: cvemodels.NvdExactVersionMatch},
|
||||
},
|
||||
Jvns: []cvemodels.Jvn{{DetectionMethod: cvemodels.JvnVendorProductMatch}},
|
||||
},
|
||||
},
|
||||
wantMax: models.NvdExactVersionMatch,
|
||||
},
|
||||
{
|
||||
name: "NvdRoughVersionMatch",
|
||||
args: args{
|
||||
detail: cvemodels.CveDetail{
|
||||
Nvds: []cvemodels.Nvd{
|
||||
{DetectionMethod: cvemodels.NvdRoughVersionMatch},
|
||||
{DetectionMethod: cvemodels.NvdVendorProductMatch},
|
||||
},
|
||||
Jvns: []cvemodels.Jvn{},
|
||||
},
|
||||
},
|
||||
wantMax: models.NvdRoughVersionMatch,
|
||||
},
|
||||
{
|
||||
name: "NvdVendorProductMatch",
|
||||
args: args{
|
||||
detail: cvemodels.CveDetail{
|
||||
Nvds: []cvemodels.Nvd{
|
||||
{DetectionMethod: cvemodels.NvdVendorProductMatch},
|
||||
},
|
||||
Jvns: []cvemodels.Jvn{{DetectionMethod: cvemodels.JvnVendorProductMatch}},
|
||||
},
|
||||
},
|
||||
wantMax: models.NvdVendorProductMatch,
|
||||
},
|
||||
{
|
||||
name: "empty",
|
||||
args: args{
|
||||
detail: cvemodels.CveDetail{
|
||||
Nvds: []cvemodels.Nvd{},
|
||||
Jvns: []cvemodels.Jvn{},
|
||||
},
|
||||
},
|
||||
wantMax: models.Confidence{},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if gotMax := getMaxConfidence(tt.args.detail); !reflect.DeepEqual(gotMax, tt.wantMax) {
|
||||
t.Errorf("getMaxConfidence() = %v, want %v", gotMax, tt.wantMax)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
224
detector/exploitdb.go
Normal file
224
detector/exploitdb.go
Normal file
@@ -0,0 +1,224 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package detector
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
exploitdb "github.com/vulsio/go-exploitdb/db"
|
||||
exploitmodels "github.com/vulsio/go-exploitdb/models"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// FillWithExploit fills exploit information that has in Exploit
|
||||
func FillWithExploit(r *models.ScanResult, cnf config.ExploitConf) (nExploitCve int, err error) {
|
||||
if cnf.IsFetchViaHTTP() {
|
||||
var cveIDs []string
|
||||
for cveID := range r.ScannedCves {
|
||||
cveIDs = append(cveIDs, cveID)
|
||||
}
|
||||
prefix, _ := util.URLPathJoin(cnf.GetURL(), "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 {
|
||||
|
||||
driver, locked, err := newExploitDB(&cnf)
|
||||
if locked {
|
||||
return 0, xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
|
||||
} else if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() {
|
||||
if err := driver.CloseDB(); err != nil {
|
||||
logging.Log.Errorf("Failed to close DB. err: %+v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type exploitResponse struct {
|
||||
request request
|
||||
json string
|
||||
}
|
||||
|
||||
func getCvesViaHTTP(cveIDs []string, urlPrefix string) (
|
||||
responses []exploitResponse, err error) {
|
||||
nReq := len(cveIDs)
|
||||
reqChan := make(chan request, nReq)
|
||||
resChan := make(chan exploitResponse, 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 {
|
||||
logging.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<- exploitResponse, errChan chan<- error) {
|
||||
var body string
|
||||
var errs []error
|
||||
var resp *http.Response
|
||||
count, retryMax := 0, 3
|
||||
f := func() (err error) {
|
||||
// resp, body, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
|
||||
resp, body, errs = gorequest.New().Timeout(10 * time.Second).Get(url).End()
|
||||
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
|
||||
count++
|
||||
if count == retryMax {
|
||||
return nil
|
||||
}
|
||||
return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %+v", url, resp, errs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
notify := func(err error, t time.Duration) {
|
||||
logging.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %+v", t, err)
|
||||
}
|
||||
err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify)
|
||||
if err != nil {
|
||||
errChan <- xerrors.Errorf("HTTP Error %w", err)
|
||||
return
|
||||
}
|
||||
if count == retryMax {
|
||||
errChan <- xerrors.New("Retry count exceeded")
|
||||
return
|
||||
}
|
||||
|
||||
resChan <- exploitResponse{
|
||||
request: req,
|
||||
json: body,
|
||||
}
|
||||
}
|
||||
|
||||
func newExploitDB(cnf config.VulnDictInterface) (driver exploitdb.DB, locked bool, err error) {
|
||||
if cnf.IsFetchViaHTTP() {
|
||||
return nil, false, nil
|
||||
}
|
||||
path := cnf.GetURL()
|
||||
if cnf.GetType() == "sqlite3" {
|
||||
path = cnf.GetSQLite3Path()
|
||||
}
|
||||
if driver, locked, err = exploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL()); err != nil {
|
||||
if locked {
|
||||
return nil, true, xerrors.Errorf("exploitDB is locked. err: %w", err)
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
return driver, false, nil
|
||||
}
|
||||
201
detector/github.go
Normal file
201
detector/github.go
Normal file
@@ -0,0 +1,201 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package detector
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/future-architect/vuls/errof"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// DetectGitHubSecurityAlerts 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 DetectGitHubSecurityAlerts(r *models.ScanResult, owner, repo, token string, ignoreDismissed bool) (nCVEs int, err error) {
|
||||
src := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: token},
|
||||
)
|
||||
//TODO Proxy
|
||||
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)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost,
|
||||
"https://api.github.com/graphql",
|
||||
bytes.NewBuffer([]byte(jsonStr)),
|
||||
)
|
||||
defer cancel()
|
||||
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 ignoreDismissed && 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
|
||||
}
|
||||
|
||||
refs := []models.Reference{}
|
||||
for _, r := range v.Node.SecurityAdvisory.References {
|
||||
refs = append(refs, models.Reference{Link: r.URL})
|
||||
}
|
||||
|
||||
for _, cveID := range cveIDs {
|
||||
cveContent := models.CveContent{
|
||||
Type: models.GitHub,
|
||||
CveID: cveID,
|
||||
Title: v.Node.SecurityAdvisory.Summary,
|
||||
Summary: v.Node.SecurityAdvisory.Description,
|
||||
Cvss2Severity: v.Node.SecurityVulnerability.Severity,
|
||||
Cvss3Severity: v.Node.SecurityVulnerability.Severity,
|
||||
SourceLink: v.Node.SecurityAdvisory.Permalink,
|
||||
References: refs,
|
||||
Published: v.Node.SecurityAdvisory.PublishedAt,
|
||||
LastModified: v.Node.SecurityAdvisory.UpdatedAt,
|
||||
}
|
||||
|
||||
if val, ok := r.ScannedCves[cveID]; ok {
|
||||
val.GitHubSecurityAlerts = val.GitHubSecurityAlerts.Add(m)
|
||||
val.CveContents[models.GitHub] = []models.CveContent{cveContent}
|
||||
r.ScannedCves[cveID] = val
|
||||
} else {
|
||||
v := models.VulnInfo{
|
||||
CveID: cveID,
|
||||
Confidences: models.Confidences{models.GitHubMatch},
|
||||
GitHubSecurityAlerts: models.GitHubSecurityAlerts{m},
|
||||
CveContents: models.NewCveContents(cveContent),
|
||||
}
|
||||
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"`
|
||||
}
|
||||
114
detector/library.go
Normal file
114
detector/library.go
Normal file
@@ -0,0 +1,114 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package detector
|
||||
|
||||
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/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
)
|
||||
|
||||
// DetectLibsCves fills LibraryScanner information
|
||||
func DetectLibsCves(r *models.ScanResult, cacheDir string, noProgress bool) (err error) {
|
||||
totalCnt := 0
|
||||
if len(r.LibraryScanners) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// initialize trivy's logger and db
|
||||
err = log.InitLogger(false, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logging.Log.Info("Updating library db...")
|
||||
if err := downloadDB("", cacheDir, noProgress, false, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := db2.Init(cacheDir); err != nil {
|
||||
return err
|
||||
}
|
||||
defer db2.Close()
|
||||
|
||||
for _, lib := range r.LibraryScanners {
|
||||
vinfos, err := lib.Scan()
|
||||
if err != nil {
|
||||
return 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)
|
||||
}
|
||||
|
||||
logging.Log.Infof("%s: %d CVEs are detected with Library",
|
||||
r.FormatServerName(), totalCnt)
|
||||
|
||||
return 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 {
|
||||
logging.Log.Info("Need to update DB")
|
||||
logging.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)
|
||||
}
|
||||
logging.Log.Debugf("DB Schema: %d, Type: %d, UpdatedAt: %s, NextUpdate: %s",
|
||||
metadata.Version, metadata.Type, metadata.UpdatedAt, metadata.NextUpdate)
|
||||
return nil
|
||||
}
|
||||
82
detector/msf.go
Normal file
82
detector/msf.go
Normal file
@@ -0,0 +1,82 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package detector
|
||||
|
||||
import (
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
metasploitdb "github.com/vulsio/go-msfdb/db"
|
||||
metasploitmodels "github.com/vulsio/go-msfdb/models"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// FillWithMetasploit fills metasploit module information that has in module
|
||||
func FillWithMetasploit(r *models.ScanResult, cnf config.MetasploitConf) (nMetasploitCve int, err error) {
|
||||
|
||||
driver, locked, err := newMetasploitDB(&cnf)
|
||||
if locked {
|
||||
return 0, xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
|
||||
} else if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() {
|
||||
if err := driver.CloseDB(); err != nil {
|
||||
logging.Log.Errorf("Failed to close DB. err: %+v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
for cveID, vuln := range r.ScannedCves {
|
||||
if cveID == "" {
|
||||
continue
|
||||
}
|
||||
ms := driver.GetModuleByCveID(cveID)
|
||||
if len(ms) == 0 {
|
||||
continue
|
||||
}
|
||||
modules := ConvertToModelsMsf(ms)
|
||||
vuln.Metasploits = modules
|
||||
r.ScannedCves[cveID] = vuln
|
||||
nMetasploitCve++
|
||||
}
|
||||
|
||||
return nMetasploitCve, nil
|
||||
}
|
||||
|
||||
// ConvertToModelsMsf converts gost model to vuls model
|
||||
func ConvertToModelsMsf(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
|
||||
}
|
||||
|
||||
func newMetasploitDB(cnf config.VulnDictInterface) (driver metasploitdb.DB, locked bool, err error) {
|
||||
if cnf.IsFetchViaHTTP() {
|
||||
return nil, false, nil
|
||||
}
|
||||
path := cnf.GetURL()
|
||||
if cnf.GetType() == "sqlite3" {
|
||||
path = cnf.GetSQLite3Path()
|
||||
}
|
||||
if driver, locked, err = metasploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL()); err != nil {
|
||||
if locked {
|
||||
return nil, true, xerrors.Errorf("metasploitDB is locked. err: %w", err)
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
return driver, false, nil
|
||||
}
|
||||
277
detector/util.go
Normal file
277
detector/util.go
Normal file
@@ -0,0 +1,277 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package detector
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/constant"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func reuseScannedCves(r *models.ScanResult) bool {
|
||||
switch r.Family {
|
||||
case constant.FreeBSD, constant.Raspbian:
|
||||
return true
|
||||
}
|
||||
if isTrivyResult(r) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isTrivyResult(r *models.ScanResult) bool {
|
||||
_, ok := r.Optional["trivy-target"]
|
||||
return ok
|
||||
}
|
||||
|
||||
func needToRefreshCve(r models.ScanResult) bool {
|
||||
for _, cve := range r.ScannedCves {
|
||||
if 0 < len(cve.CveContents) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func loadPrevious(currs models.ScanResults, resultsDir string) (prevs models.ScanResults, err error) {
|
||||
dirs, err := ListValidJSONDirs(resultsDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, result := range currs {
|
||||
filename := result.ServerName + ".json"
|
||||
if result.Container.Name != "" {
|
||||
filename = fmt.Sprintf("%s@%s.json", result.Container.Name, result.ServerName)
|
||||
}
|
||||
for _, dir := range dirs[1:] {
|
||||
path := filepath.Join(dir, filename)
|
||||
r, err := loadOneServerScanResult(path)
|
||||
if err != nil {
|
||||
logging.Log.Debugf("%+v", err)
|
||||
continue
|
||||
}
|
||||
if r.Family == result.Family && r.Release == result.Release {
|
||||
prevs = append(prevs, *r)
|
||||
logging.Log.Infof("Previous json found: %s", path)
|
||||
break
|
||||
}
|
||||
logging.Log.Infof("Previous json is different family.Release: %s, pre: %s.%s cur: %s.%s",
|
||||
path, r.Family, r.Release, result.Family, result.Release)
|
||||
}
|
||||
}
|
||||
return prevs, nil
|
||||
}
|
||||
|
||||
func diff(curResults, preResults models.ScanResults, isPlus, isMinus bool) (diffed models.ScanResults) {
|
||||
for _, current := range curResults {
|
||||
found := false
|
||||
var previous models.ScanResult
|
||||
for _, r := range preResults {
|
||||
if current.ServerName == r.ServerName && current.Container.Name == r.Container.Name {
|
||||
found = true
|
||||
previous = r
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
diffed = append(diffed, current)
|
||||
continue
|
||||
}
|
||||
|
||||
cves := models.VulnInfos{}
|
||||
if isPlus {
|
||||
cves = getPlusDiffCves(previous, current)
|
||||
}
|
||||
if isMinus {
|
||||
minus := getMinusDiffCves(previous, current)
|
||||
if len(cves) == 0 {
|
||||
cves = minus
|
||||
} else {
|
||||
for k, v := range minus {
|
||||
cves[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
packages := models.Packages{}
|
||||
for _, s := range cves {
|
||||
for _, affected := range s.AffectedPackages {
|
||||
var p models.Package
|
||||
if s.DiffStatus == models.DiffPlus {
|
||||
p = current.Packages[affected.Name]
|
||||
} else {
|
||||
p = previous.Packages[affected.Name]
|
||||
}
|
||||
packages[affected.Name] = p
|
||||
}
|
||||
}
|
||||
current.ScannedCves = cves
|
||||
current.Packages = packages
|
||||
diffed = append(diffed, current)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getPlusDiffCves(previous, current models.ScanResult) models.VulnInfos {
|
||||
previousCveIDsSet := map[string]bool{}
|
||||
for _, previousVulnInfo := range previous.ScannedCves {
|
||||
previousCveIDsSet[previousVulnInfo.CveID] = true
|
||||
}
|
||||
|
||||
new := models.VulnInfos{}
|
||||
updated := models.VulnInfos{}
|
||||
for _, v := range current.ScannedCves {
|
||||
if previousCveIDsSet[v.CveID] {
|
||||
if isCveInfoUpdated(v.CveID, previous, current) {
|
||||
v.DiffStatus = models.DiffPlus
|
||||
updated[v.CveID] = v
|
||||
logging.Log.Debugf("updated: %s", v.CveID)
|
||||
|
||||
// TODO commented out because a bug of diff logic when multiple oval defs found for a certain CVE-ID and same updated_at
|
||||
// if these OVAL defs have different affected packages, this logic detects as updated.
|
||||
// This logic will be uncomented after integration with gost https://github.com/vulsio/gost
|
||||
// } else if isCveFixed(v, previous) {
|
||||
// updated[v.CveID] = v
|
||||
// logging.Log.Debugf("fixed: %s", v.CveID)
|
||||
|
||||
} else {
|
||||
logging.Log.Debugf("same: %s", v.CveID)
|
||||
}
|
||||
} else {
|
||||
logging.Log.Debugf("new: %s", v.CveID)
|
||||
v.DiffStatus = models.DiffPlus
|
||||
new[v.CveID] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(updated) == 0 && len(new) == 0 {
|
||||
logging.Log.Infof("%s: There are %d vulnerabilities, but no difference between current result and previous one.", current.FormatServerName(), len(current.ScannedCves))
|
||||
}
|
||||
|
||||
for cveID, vuln := range new {
|
||||
updated[cveID] = vuln
|
||||
}
|
||||
return updated
|
||||
}
|
||||
|
||||
func getMinusDiffCves(previous, current models.ScanResult) models.VulnInfos {
|
||||
currentCveIDsSet := map[string]bool{}
|
||||
for _, currentVulnInfo := range current.ScannedCves {
|
||||
currentCveIDsSet[currentVulnInfo.CveID] = true
|
||||
}
|
||||
|
||||
clear := models.VulnInfos{}
|
||||
for _, v := range previous.ScannedCves {
|
||||
if !currentCveIDsSet[v.CveID] {
|
||||
v.DiffStatus = models.DiffMinus
|
||||
clear[v.CveID] = v
|
||||
logging.Log.Debugf("clear: %s", v.CveID)
|
||||
}
|
||||
}
|
||||
if len(clear) == 0 {
|
||||
logging.Log.Infof("%s: There are %d vulnerabilities, but no difference between current result and previous one.", current.FormatServerName(), len(current.ScannedCves))
|
||||
}
|
||||
|
||||
return clear
|
||||
}
|
||||
|
||||
func isCveInfoUpdated(cveID string, previous, current models.ScanResult) bool {
|
||||
cTypes := []models.CveContentType{
|
||||
models.Nvd,
|
||||
models.Jvn,
|
||||
models.NewCveContentType(current.Family),
|
||||
}
|
||||
|
||||
prevLastModified := map[models.CveContentType][]time.Time{}
|
||||
preVinfo, ok := previous.ScannedCves[cveID]
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
for _, cType := range cTypes {
|
||||
if conts, ok := preVinfo.CveContents[cType]; ok {
|
||||
for _, cont := range conts {
|
||||
prevLastModified[cType] = append(prevLastModified[cType], cont.LastModified)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
curLastModified := map[models.CveContentType][]time.Time{}
|
||||
curVinfo, ok := current.ScannedCves[cveID]
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
for _, cType := range cTypes {
|
||||
if conts, ok := curVinfo.CveContents[cType]; ok {
|
||||
for _, cont := range conts {
|
||||
curLastModified[cType] = append(curLastModified[cType], cont.LastModified)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, t := range cTypes {
|
||||
if !reflect.DeepEqual(curLastModified[t], prevLastModified[t]) {
|
||||
logging.Log.Debugf("%s LastModified not equal: \n%s\n%s",
|
||||
cveID, curLastModified[t], prevLastModified[t])
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// jsonDirPattern is file name pattern of JSON directory
|
||||
// 2016-11-16T10:43:28+09:00
|
||||
// 2016-11-16T10:43:28Z
|
||||
var jsonDirPattern = regexp.MustCompile(
|
||||
`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:Z|[+-]\d{2}:\d{2})$`)
|
||||
|
||||
// ListValidJSONDirs returns valid json directory as array
|
||||
// Returned array is sorted so that recent directories are at the head
|
||||
func ListValidJSONDirs(resultsDir string) (dirs []string, err error) {
|
||||
var dirInfo []os.FileInfo
|
||||
if dirInfo, err = ioutil.ReadDir(resultsDir); err != nil {
|
||||
err = xerrors.Errorf("Failed to read %s: %w",
|
||||
config.Conf.ResultsDir, err)
|
||||
return
|
||||
}
|
||||
for _, d := range dirInfo {
|
||||
if d.IsDir() && jsonDirPattern.MatchString(d.Name()) {
|
||||
jsonDir := filepath.Join(resultsDir, d.Name())
|
||||
dirs = append(dirs, jsonDir)
|
||||
}
|
||||
}
|
||||
sort.Slice(dirs, func(i, j int) bool {
|
||||
return dirs[j] < dirs[i]
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// loadOneServerScanResult read JSON data of one server
|
||||
func loadOneServerScanResult(jsonFile string) (*models.ScanResult, error) {
|
||||
var (
|
||||
data []byte
|
||||
err error
|
||||
)
|
||||
if data, err = ioutil.ReadFile(jsonFile); err != nil {
|
||||
return nil, xerrors.Errorf("Failed to read %s: %w", jsonFile, err)
|
||||
}
|
||||
result := &models.ScanResult{}
|
||||
if err := json.Unmarshal(data, result); err != nil {
|
||||
return nil, xerrors.Errorf("Failed to parse %s: %w", jsonFile, err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
273
detector/wordpress.go
Normal file
273
detector/wordpress.go
Normal file
@@ -0,0 +1,273 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package detector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/errof"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
version "github.com/hashicorp/go-version"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
//WpCveInfos is for wpscan json
|
||||
type WpCveInfos struct {
|
||||
ReleaseDate string `json:"release_date"`
|
||||
ChangelogURL string `json:"changelog_url"`
|
||||
// Status string `json:"status"`
|
||||
LatestVersion string `json:"latest_version"`
|
||||
LastUpdated string `json:"last_updated"`
|
||||
// Popular bool `json:"popular"`
|
||||
Vulnerabilities []WpCveInfo `json:"vulnerabilities"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
//WpCveInfo is for wpscan json
|
||||
type WpCveInfo struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
VulnType string `json:"vuln_type"`
|
||||
References References `json:"references"`
|
||||
FixedIn string `json:"fixed_in"`
|
||||
}
|
||||
|
||||
//References is for wpscan json
|
||||
type References struct {
|
||||
URL []string `json:"url"`
|
||||
Cve []string `json:"cve"`
|
||||
Secunia []string `json:"secunia"`
|
||||
}
|
||||
|
||||
// DetectWordPressCves access to wpscan and fetch scurity alerts and then set to the given ScanResult.
|
||||
// https://wpscan.com/
|
||||
func detectWordPressCves(r *models.ScanResult, cnf config.WpScanConf) (int, error) {
|
||||
if len(r.WordPressPackages) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
// Core
|
||||
ver := strings.Replace(r.WordPressPackages.CoreVersion(), ".", "", -1)
|
||||
if ver == "" {
|
||||
return 0, errof.New(errof.ErrFailedToAccessWpScan,
|
||||
fmt.Sprintf("Failed to get WordPress core version."))
|
||||
}
|
||||
url := fmt.Sprintf("https://wpscan.com/api/v3/wordpresses/%s", ver)
|
||||
wpVinfos, err := wpscan(url, ver, cnf.Token, true)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Themes
|
||||
themes := r.WordPressPackages.Themes()
|
||||
if !cnf.DetectInactive {
|
||||
themes = removeInactives(themes)
|
||||
}
|
||||
for _, p := range themes {
|
||||
url := fmt.Sprintf("https://wpscan.com/api/v3/themes/%s", p.Name)
|
||||
candidates, err := wpscan(url, p.Name, cnf.Token, false)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
vulns := detect(p, candidates)
|
||||
wpVinfos = append(wpVinfos, vulns...)
|
||||
}
|
||||
|
||||
// Plugins
|
||||
plugins := r.WordPressPackages.Plugins()
|
||||
if !cnf.DetectInactive {
|
||||
plugins = removeInactives(plugins)
|
||||
}
|
||||
for _, p := range plugins {
|
||||
url := fmt.Sprintf("https://wpscan.com/api/v3/plugins/%s", p.Name)
|
||||
candidates, err := wpscan(url, p.Name, cnf.Token, false)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
vulns := detect(p, candidates)
|
||||
wpVinfos = append(wpVinfos, vulns...)
|
||||
}
|
||||
|
||||
for _, wpVinfo := range wpVinfos {
|
||||
if vinfo, ok := r.ScannedCves[wpVinfo.CveID]; ok {
|
||||
vinfo.CveContents[models.WpScan] = wpVinfo.CveContents[models.WpScan]
|
||||
vinfo.VulnType = wpVinfo.VulnType
|
||||
vinfo.Confidences = append(vinfo.Confidences, wpVinfo.Confidences...)
|
||||
vinfo.WpPackageFixStats = append(vinfo.WpPackageFixStats, wpVinfo.WpPackageFixStats...)
|
||||
r.ScannedCves[wpVinfo.CveID] = vinfo
|
||||
} else {
|
||||
r.ScannedCves[wpVinfo.CveID] = wpVinfo
|
||||
}
|
||||
}
|
||||
return len(wpVinfos), nil
|
||||
}
|
||||
|
||||
func wpscan(url, name, token string, isCore bool) (vinfos []models.VulnInfo, err error) {
|
||||
body, err := httpRequest(url, token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if body == "" {
|
||||
logging.Log.Debugf("wpscan.com response body is empty. URL: %s", url)
|
||||
}
|
||||
if isCore {
|
||||
name = "core"
|
||||
}
|
||||
return convertToVinfos(name, body)
|
||||
}
|
||||
|
||||
func detect(installed models.WpPackage, candidates []models.VulnInfo) (vulns []models.VulnInfo) {
|
||||
for _, v := range candidates {
|
||||
for _, fixstat := range v.WpPackageFixStats {
|
||||
ok, err := match(installed.Version, fixstat.FixedIn)
|
||||
if err != nil {
|
||||
logging.Log.Warnf("Failed to compare versions %s installed: %s, fixedIn: %s, v: %+v",
|
||||
installed.Name, installed.Version, fixstat.FixedIn, v)
|
||||
// continue scanning
|
||||
continue
|
||||
}
|
||||
if ok {
|
||||
vulns = append(vulns, v)
|
||||
logging.Log.Debugf("Affected: %s installed: %s, fixedIn: %s",
|
||||
installed.Name, installed.Version, fixstat.FixedIn)
|
||||
} else {
|
||||
logging.Log.Debugf("Not affected: %s : %s, fixedIn: %s",
|
||||
installed.Name, installed.Version, fixstat.FixedIn)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func match(installedVer, fixedIn string) (bool, error) {
|
||||
v1, err := version.NewVersion(installedVer)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
v2, err := version.NewVersion(fixedIn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return v1.LessThan(v2), nil
|
||||
}
|
||||
|
||||
func convertToVinfos(pkgName, body string) (vinfos []models.VulnInfo, err error) {
|
||||
if body == "" {
|
||||
return
|
||||
}
|
||||
// "pkgName" : CVE Detailed data
|
||||
pkgnameCves := map[string]WpCveInfos{}
|
||||
if err = json.Unmarshal([]byte(body), &pkgnameCves); err != nil {
|
||||
return nil, xerrors.Errorf("Failed to unmarshal %s. err: %w", body, err)
|
||||
}
|
||||
|
||||
for _, v := range pkgnameCves {
|
||||
vs := extractToVulnInfos(pkgName, v.Vulnerabilities)
|
||||
vinfos = append(vinfos, vs...)
|
||||
}
|
||||
return vinfos, nil
|
||||
}
|
||||
|
||||
func extractToVulnInfos(pkgName string, cves []WpCveInfo) (vinfos []models.VulnInfo) {
|
||||
for _, vulnerability := range cves {
|
||||
var cveIDs []string
|
||||
|
||||
if len(vulnerability.References.Cve) == 0 {
|
||||
cveIDs = append(cveIDs, fmt.Sprintf("WPVDBID-%s", vulnerability.ID))
|
||||
}
|
||||
for _, cveNumber := range vulnerability.References.Cve {
|
||||
cveIDs = append(cveIDs, "CVE-"+cveNumber)
|
||||
}
|
||||
|
||||
var refs []models.Reference
|
||||
for _, url := range vulnerability.References.URL {
|
||||
refs = append(refs, models.Reference{
|
||||
Link: url,
|
||||
})
|
||||
}
|
||||
|
||||
for _, cveID := range cveIDs {
|
||||
vinfos = append(vinfos, models.VulnInfo{
|
||||
CveID: cveID,
|
||||
CveContents: models.NewCveContents(
|
||||
models.CveContent{
|
||||
Type: models.WpScan,
|
||||
CveID: cveID,
|
||||
Title: vulnerability.Title,
|
||||
References: refs,
|
||||
Published: vulnerability.CreatedAt,
|
||||
LastModified: vulnerability.UpdatedAt,
|
||||
},
|
||||
),
|
||||
VulnType: vulnerability.VulnType,
|
||||
Confidences: []models.Confidence{
|
||||
models.WpScanMatch,
|
||||
},
|
||||
WpPackageFixStats: []models.WpPackageFixStatus{{
|
||||
Name: pkgName,
|
||||
FixedIn: vulnerability.FixedIn,
|
||||
}},
|
||||
})
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func httpRequest(url, token string) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
defer cancel()
|
||||
if err != nil {
|
||||
return "", errof.New(errof.ErrFailedToAccessWpScan,
|
||||
fmt.Sprintf("Failed to access to wpscan.com. err: %s", err))
|
||||
}
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Token token=%s", token))
|
||||
client, err := util.GetHTTPClient(config.Conf.HTTPProxy)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", errof.New(errof.ErrFailedToAccessWpScan,
|
||||
fmt.Sprintf("Failed to access to wpscan.com. err: %s", err))
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", errof.New(errof.ErrFailedToAccessWpScan,
|
||||
fmt.Sprintf("Failed to access to wpscan.com. err: %s", err))
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode == 200 {
|
||||
return string(body), nil
|
||||
} else if resp.StatusCode == 404 {
|
||||
// This package is not in wpscan
|
||||
return "", nil
|
||||
} else if resp.StatusCode == 429 {
|
||||
return "", errof.New(errof.ErrWpScanAPILimitExceeded,
|
||||
fmt.Sprintf("wpscan.com API limit exceeded: %+v", resp.Status))
|
||||
} else {
|
||||
logging.Log.Warnf("wpscan.com unknown status code: %+v", resp.Status)
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
func removeInactives(pkgs models.WordPressPackages) (removed models.WordPressPackages) {
|
||||
for _, p := range pkgs {
|
||||
if p.Status == "inactive" {
|
||||
continue
|
||||
}
|
||||
removed = append(removed, p)
|
||||
}
|
||||
return removed
|
||||
}
|
||||
84
detector/wordpress_test.go
Normal file
84
detector/wordpress_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package detector
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/future-architect/vuls/models"
|
||||
)
|
||||
|
||||
func TestRemoveInactive(t *testing.T) {
|
||||
var tests = []struct {
|
||||
in models.WordPressPackages
|
||||
expected models.WordPressPackages
|
||||
}{
|
||||
{
|
||||
in: models.WordPressPackages{
|
||||
{
|
||||
Name: "akismet",
|
||||
Status: "inactive",
|
||||
Update: "",
|
||||
Version: "",
|
||||
Type: "",
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
in: models.WordPressPackages{
|
||||
{
|
||||
Name: "akismet",
|
||||
Status: "inactive",
|
||||
Update: "",
|
||||
Version: "",
|
||||
Type: "",
|
||||
},
|
||||
{
|
||||
Name: "BackWPup",
|
||||
Status: "inactive",
|
||||
Update: "",
|
||||
Version: "",
|
||||
Type: "",
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
in: models.WordPressPackages{
|
||||
{
|
||||
Name: "akismet",
|
||||
Status: "active",
|
||||
Update: "",
|
||||
Version: "",
|
||||
Type: "",
|
||||
},
|
||||
{
|
||||
Name: "BackWPup",
|
||||
Status: "inactive",
|
||||
Update: "",
|
||||
Version: "",
|
||||
Type: "",
|
||||
},
|
||||
},
|
||||
expected: models.WordPressPackages{
|
||||
{
|
||||
Name: "akismet",
|
||||
Status: "active",
|
||||
Update: "",
|
||||
Version: "",
|
||||
Type: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
actual := removeInactives(tt.in)
|
||||
if !reflect.DeepEqual(actual, tt.expected) {
|
||||
t.Errorf("[%d] WordPressPackages error ", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
33
errof/errof.go
Normal file
33
errof/errof.go
Normal file
@@ -0,0 +1,33 @@
|
||||
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"
|
||||
|
||||
// ErrFailedToAccessWpScan is error of wpscan.com api access
|
||||
ErrFailedToAccessWpScan ErrorCode = "ErrFailedToAccessWpScan"
|
||||
|
||||
// ErrWpScanAPILimitExceeded is error of wpscan.com api limit exceeded
|
||||
ErrWpScanAPILimitExceeded ErrorCode = "ErrWpScanAPILimitExceeded"
|
||||
)
|
||||
|
||||
// New :
|
||||
func New(code ErrorCode, msg string) Error {
|
||||
return Error{
|
||||
Code: code,
|
||||
Message: msg,
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Architect, Inc. Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
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 fmt.Errorf("Failed to connect to exploit server. url: %s, errs: %v",
|
||||
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
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package exploit
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSetPackageStates(t *testing.T) {
|
||||
}
|
||||
133
exploit/util.go
133
exploit/util.go
@@ -1,133 +0,0 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Architect, Inc. Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package exploit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/future-architect/vuls/util"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
)
|
||||
|
||||
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, fmt.Errorf("Timeout Fetching OVAL")
|
||||
}
|
||||
}
|
||||
if len(errs) != 0 {
|
||||
return nil, fmt.Errorf("Failed to fetch OVAL. err: %v", 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 fmt.Errorf("HTTP GET error: %v, url: %s, resp: %v",
|
||||
errs, url, resp)
|
||||
}
|
||||
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 <- fmt.Errorf("HTTP Error %s", err)
|
||||
return
|
||||
}
|
||||
if count == retryMax {
|
||||
errChan <- fmt.Errorf("HRetry count exceeded")
|
||||
return
|
||||
}
|
||||
|
||||
resChan <- response{
|
||||
request: req,
|
||||
json: body,
|
||||
}
|
||||
}
|
||||
144
github/github.go
144
github/github.go
@@ -1,144 +0,0 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package github
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
"github.com/k0kubun/pp"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// FillGitHubSecurityAlerts access to owner/repo on GitHub and fetch scurity 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
|
||||
const jsonfmt = `{"query":
|
||||
"query { repository(owner:\"%s\", name:\"%s\") { url, vulnerabilityAlerts(first: %d, %s) { pageInfo{ endCursor, hasNextPage, startCursor}, edges { node { id, externalIdentifier, externalReference, fixedIn, packageName, dismissReason, dismissedAt } } } } }"}`
|
||||
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.vixen-preview+json")
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
alerts := SecurityAlerts{}
|
||||
if json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
util.Log.Debugf("%s", pp.Sprint(alerts))
|
||||
|
||||
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.PackageName)
|
||||
|
||||
m := models.GitHubSecurityAlert{
|
||||
PackageName: pkgName,
|
||||
FixedIn: v.Node.FixedIn,
|
||||
AffectedRange: v.Node.AffectedRange,
|
||||
Dismissed: len(v.Node.DismissReason) != 0,
|
||||
DismissedAt: v.Node.DismissedAt,
|
||||
DismissReason: v.Node.DismissReason,
|
||||
}
|
||||
|
||||
cveID := v.Node.ExternalIdentifier
|
||||
|
||||
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,omitempty"`
|
||||
VulnerabilityAlerts struct {
|
||||
PageInfo struct {
|
||||
EndCursor string `json:"endCursor,omitempty"`
|
||||
HasNextPage bool `json:"hasNextPage,omitempty"`
|
||||
StartCursor string `json:"startCursor,omitempty"`
|
||||
} `json:"pageInfo,omitempty"`
|
||||
Edges []struct {
|
||||
Node struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
ExternalIdentifier string `json:"externalIdentifier,omitempty"`
|
||||
ExternalReference string `json:"externalReference,omitempty"`
|
||||
FixedIn string `json:"fixedIn,omitempty"`
|
||||
AffectedRange string `json:"affectedRange,omitempty"`
|
||||
PackageName string `json:"packageName,omitempty"`
|
||||
DismissReason string `json:"dismissReason,omitempty"`
|
||||
DismissedAt time.Time `json:"dismissedAt,omitempty"`
|
||||
} `json:"node,omitempty"`
|
||||
} `json:"edges,omitempty"`
|
||||
} `json:"vulnerabilityAlerts,omitempty"`
|
||||
} `json:"repository,omitempty"`
|
||||
} `json:"data,omitempty"`
|
||||
}
|
||||
153
go.mod
Normal file
153
go.mod
Normal file
@@ -0,0 +1,153 @@
|
||||
module github.com/future-architect/vuls
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go v50.2.0+incompatible
|
||||
github.com/BurntSushi/toml v0.4.1
|
||||
github.com/Ullaakut/nmap/v2 v2.1.2-0.20210406060955-59a52fe80a4f
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/aquasecurity/fanal v0.0.0-20210815095355-42429a80d0e3
|
||||
github.com/aquasecurity/trivy v0.19.3-0.20210909113250-19c0b70d2613
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20210809142931-da8e09204404
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
|
||||
github.com/aws/aws-sdk-go v1.40.22
|
||||
github.com/boltdb/bolt v1.3.1
|
||||
github.com/briandowns/spinner v1.16.0 // indirect
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cheggaaa/pb/v3 v3.0.8 // indirect
|
||||
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
|
||||
github.com/emersion/go-smtp v0.14.0
|
||||
github.com/fatih/color v1.12.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/go-redis/redis/v8 v8.11.3 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/google/subcommands v1.2.0
|
||||
github.com/gosuri/uitable v0.0.4
|
||||
github.com/hashicorp/go-uuid v1.0.2
|
||||
github.com/hashicorp/go-version v1.3.0
|
||||
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c
|
||||
github.com/jesseduffield/gocui v0.3.0
|
||||
github.com/k0kubun/pp v3.0.1+incompatible
|
||||
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f
|
||||
github.com/knqyf263/go-cpe v0.0.0-20201213041631-54f6ab28673f
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
|
||||
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936
|
||||
github.com/kotakanbe/go-pingscanner v0.1.0
|
||||
github.com/kotakanbe/logrus-prefixed-formatter v0.0.0-20180123152602-928f7356cb96
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/nlopes/slack v0.6.0
|
||||
github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/parnurzeal/gorequest v0.2.16
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spf13/afero v1.6.0
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/cobra v1.2.1
|
||||
github.com/vulsio/go-cve-dictionary v0.8.1
|
||||
github.com/vulsio/go-exploitdb v0.4.0
|
||||
github.com/vulsio/go-msfdb v0.2.0
|
||||
github.com/vulsio/gost v0.4.1-0.20210919121048-2a7957bf1885
|
||||
github.com/vulsio/goval-dictionary v0.6.1
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||
golang.org/x/net v0.0.0-20210902165921-8d991716f632 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||
gorm.io/driver/mysql v1.1.2 // indirect
|
||||
gorm.io/driver/postgres v1.1.1 // indirect
|
||||
gorm.io/driver/sqlite v1.1.5 // indirect
|
||||
k8s.io/utils v0.0.0-20210111153108-fddb29f9d009
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.1 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.5 // indirect
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.0 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||
github.com/PuerkitoBio/goquery v1.7.1 // indirect
|
||||
github.com/andybalholm/cascadia v1.2.0 // indirect
|
||||
github.com/aquasecurity/go-dep-parser v0.0.0-20210815080135-5be65146849a // indirect
|
||||
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce // indirect
|
||||
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 // indirect
|
||||
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 // indirect
|
||||
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect
|
||||
github.com/caarlos0/env/v6 v6.0.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect
|
||||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/go-github/v33 v33.0.0 // indirect
|
||||
github.com/google/go-querystring v1.0.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/google/wire v0.4.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/grokify/html-strip-tags-go v0.0.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.6.8 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/htcat/htcat v1.0.2 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgconn v1.10.0 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.1.1 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
||||
github.com/jackc/pgtype v1.8.1 // indirect
|
||||
github.com/jackc/pgx/v4 v4.13.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.2 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||
github.com/mitchellh/copystructure v1.1.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.2 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/satori/go.uuid v1.2.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.8.1 // indirect
|
||||
github.com/stretchr/objx v0.3.0 // indirect
|
||||
github.com/stretchr/testify v1.7.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/ymomoi/goval-parser v0.0.0-20170813122243-0a0be1dd9d08 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.17.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 // indirect
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.26.0 // indirect
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
gorm.io/gorm v1.21.15 // indirect
|
||||
moul.io/http2curl v1.0.0 // indirect
|
||||
)
|
||||
204
gost/debian.go
204
gost/debian.go
@@ -1,30 +1,17 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Architect, Inc. Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package gost
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
"github.com/knqyf263/gost/db"
|
||||
gostmodels "github.com/knqyf263/gost/models"
|
||||
debver "github.com/knqyf263/go-deb-version"
|
||||
gostmodels "github.com/vulsio/gost/models"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// Debian is Gost client for Debian GNU/Linux
|
||||
@@ -36,15 +23,31 @@ type packCves struct {
|
||||
packName string
|
||||
isSrcPack bool
|
||||
cves []models.CveContent
|
||||
fixes models.PackageFixStatuses
|
||||
}
|
||||
|
||||
// FillWithGost fills cve information that has in Gost
|
||||
func (deb Debian) FillWithGost(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
|
||||
linuxImage := "linux-image-" + r.RunningKernel.Release
|
||||
// Add linux and set the version of running kernel to search OVAL.
|
||||
func (deb Debian) supported(major string) bool {
|
||||
_, ok := map[string]string{
|
||||
"8": "jessie",
|
||||
"9": "stretch",
|
||||
"10": "buster",
|
||||
"11": "bullseye",
|
||||
}[major]
|
||||
return ok
|
||||
}
|
||||
|
||||
// DetectCVEs fills cve information that has in Gost
|
||||
func (deb Debian) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) {
|
||||
if !deb.supported(major(r.Release)) {
|
||||
// only logging
|
||||
logging.Log.Warnf("Debian %s is not supported yet", r.Release)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Add linux and set the version of running kernel to search Gost.
|
||||
if r.Container.ContainerID == "" {
|
||||
newVer := ""
|
||||
if p, ok := r.Packages[linuxImage]; ok {
|
||||
if p, ok := r.Packages["linux-image-"+r.RunningKernel.Release]; ok {
|
||||
newVer = p.NewVersion
|
||||
}
|
||||
r.Packages["linux"] = models.Package{
|
||||
@@ -54,10 +57,35 @@ func (deb Debian) FillWithGost(driver db.DB, r *models.ScanResult) (nCVEs int, e
|
||||
}
|
||||
}
|
||||
|
||||
stashLinuxPackage := r.Packages["linux"]
|
||||
nFixedCVEs, err := deb.detectCVEsWithFixState(r, "resolved")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
r.Packages["linux"] = stashLinuxPackage
|
||||
nUnfixedCVEs, err := deb.detectCVEsWithFixState(r, "open")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return (nFixedCVEs + nUnfixedCVEs), nil
|
||||
}
|
||||
|
||||
func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string) (nCVEs int, err error) {
|
||||
if fixStatus != "resolved" && fixStatus != "open" {
|
||||
return 0, xerrors.Errorf(`Failed to detectCVEsWithFixState. fixStatus is not allowed except "open" and "resolved"(actual: fixStatus -> %s).`, fixStatus)
|
||||
}
|
||||
|
||||
packCvesList := []packCves{}
|
||||
if config.Conf.Gost.IsFetchViaHTTP() {
|
||||
url, _ := util.URLPathJoin(config.Conf.Gost.URL, "debian", major(r.Release), "pkgs")
|
||||
responses, err := getAllUnfixedCvesViaHTTP(r, url)
|
||||
if deb.DBDriver.Cnf.IsFetchViaHTTP() {
|
||||
url, _ := util.URLPathJoin(deb.DBDriver.Cnf.GetURL(), "debian", major(r.Release), "pkgs")
|
||||
s := "unfixed-cves"
|
||||
if s == "resolved" {
|
||||
s = "fixed-cves"
|
||||
}
|
||||
|
||||
responses, err := getCvesWithFixStateViaHTTP(r, url, s)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -68,43 +96,40 @@ func (deb Debian) FillWithGost(driver db.DB, r *models.ScanResult) (nCVEs int, e
|
||||
return 0, err
|
||||
}
|
||||
cves := []models.CveContent{}
|
||||
fixes := []models.PackageFixStatus{}
|
||||
for _, debcve := range debCves {
|
||||
cves = append(cves, *deb.ConvertToModel(&debcve))
|
||||
fixes = append(fixes, checkPackageFixStatus(&debcve)...)
|
||||
}
|
||||
packCvesList = append(packCvesList, packCves{
|
||||
packName: res.request.packName,
|
||||
isSrcPack: res.request.isSrcPack,
|
||||
cves: cves,
|
||||
fixes: fixes,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if driver == nil {
|
||||
if deb.DBDriver.DB == nil {
|
||||
return 0, nil
|
||||
}
|
||||
for _, pack := range r.Packages {
|
||||
cveDebs := driver.GetUnfixedCvesDebian(major(r.Release), pack.Name)
|
||||
cves := []models.CveContent{}
|
||||
for _, cveDeb := range cveDebs {
|
||||
cves = append(cves, *deb.ConvertToModel(&cveDeb))
|
||||
}
|
||||
cves, fixes := deb.getCvesDebianWithfixStatus(fixStatus, major(r.Release), pack.Name)
|
||||
packCvesList = append(packCvesList, packCves{
|
||||
packName: pack.Name,
|
||||
isSrcPack: false,
|
||||
cves: cves,
|
||||
fixes: fixes,
|
||||
})
|
||||
}
|
||||
|
||||
// SrcPack
|
||||
for _, pack := range r.SrcPackages {
|
||||
cveDebs := driver.GetUnfixedCvesDebian(major(r.Release), pack.Name)
|
||||
cves := []models.CveContent{}
|
||||
for _, cveDeb := range cveDebs {
|
||||
cves = append(cves, *deb.ConvertToModel(&cveDeb))
|
||||
}
|
||||
cves, fixes := deb.getCvesDebianWithfixStatus(fixStatus, major(r.Release), pack.Name)
|
||||
packCvesList = append(packCvesList, packCves{
|
||||
packName: pack.Name,
|
||||
isSrcPack: true,
|
||||
cves: cves,
|
||||
fixes: fixes,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -112,13 +137,14 @@ func (deb Debian) FillWithGost(driver db.DB, r *models.ScanResult) (nCVEs int, e
|
||||
delete(r.Packages, "linux")
|
||||
|
||||
for _, p := range packCvesList {
|
||||
for _, cve := range p.cves {
|
||||
for i, 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
|
||||
v.CveContents[models.DebianSecurityTracker] = []models.CveContent{cve}
|
||||
v.Confidences = models.Confidences{models.DebianSecurityTrackerMatch}
|
||||
}
|
||||
} else {
|
||||
v = models.VulnInfo{
|
||||
@@ -126,6 +152,31 @@ func (deb Debian) FillWithGost(driver db.DB, r *models.ScanResult) (nCVEs int, e
|
||||
CveContents: models.NewCveContents(cve),
|
||||
Confidences: models.Confidences{models.DebianSecurityTrackerMatch},
|
||||
}
|
||||
|
||||
if fixStatus == "resolved" {
|
||||
versionRelease := ""
|
||||
if p.isSrcPack {
|
||||
versionRelease = r.SrcPackages[p.packName].Version
|
||||
} else {
|
||||
versionRelease = r.Packages[p.packName].FormatVer()
|
||||
}
|
||||
|
||||
if versionRelease == "" {
|
||||
break
|
||||
}
|
||||
|
||||
affected, err := isGostDefAffected(versionRelease, p.fixes[i].FixedIn)
|
||||
if err != nil {
|
||||
logging.Log.Debugf("Failed to parse versions: %s, Ver: %s, Gost: %s",
|
||||
err, versionRelease, p.fixes[i].FixedIn)
|
||||
continue
|
||||
}
|
||||
|
||||
if !affected {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
nCVEs++
|
||||
}
|
||||
|
||||
@@ -140,25 +191,65 @@ func (deb Debian) FillWithGost(driver db.DB, r *models.ScanResult) (nCVEs int, e
|
||||
}
|
||||
} else {
|
||||
if p.packName == "linux" {
|
||||
names = append(names, linuxImage)
|
||||
names = append(names, "linux-image-"+r.RunningKernel.Release)
|
||||
} else {
|
||||
names = append(names, p.packName)
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
v.AffectedPackages = v.AffectedPackages.Store(models.PackageStatus{
|
||||
Name: name,
|
||||
FixState: "open",
|
||||
NotFixedYet: true,
|
||||
})
|
||||
if fixStatus == "resolved" {
|
||||
for _, name := range names {
|
||||
v.AffectedPackages = v.AffectedPackages.Store(models.PackageFixStatus{
|
||||
Name: name,
|
||||
FixedIn: p.fixes[i].FixedIn,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
for _, name := range names {
|
||||
v.AffectedPackages = v.AffectedPackages.Store(models.PackageFixStatus{
|
||||
Name: name,
|
||||
FixState: "open",
|
||||
NotFixedYet: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
r.ScannedCves[cve.CveID] = v
|
||||
}
|
||||
}
|
||||
|
||||
return nCVEs, nil
|
||||
}
|
||||
|
||||
func isGostDefAffected(versionRelease, gostVersion string) (affected bool, err error) {
|
||||
vera, err := debver.NewVersion(versionRelease)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
verb, err := debver.NewVersion(gostVersion)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return vera.LessThan(verb), nil
|
||||
}
|
||||
|
||||
func (deb Debian) getCvesDebianWithfixStatus(fixStatus, release, pkgName string) (cves []models.CveContent, fixes []models.PackageFixStatus) {
|
||||
var f func(string, string) map[string]gostmodels.DebianCVE
|
||||
|
||||
if fixStatus == "resolved" {
|
||||
f = deb.DBDriver.DB.GetFixedCvesDebian
|
||||
} else {
|
||||
f = deb.DBDriver.DB.GetUnfixedCvesDebian
|
||||
}
|
||||
|
||||
for _, cveDeb := range f(release, pkgName) {
|
||||
cves = append(cves, *deb.ConvertToModel(&cveDeb))
|
||||
fixes = append(fixes, checkPackageFixStatus(&cveDeb)...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ConvertToModel converts gost model to vuls model
|
||||
func (deb Debian) ConvertToModel(cve *gostmodels.DebianCVE) *models.CveContent {
|
||||
severity := ""
|
||||
@@ -180,3 +271,22 @@ func (deb Debian) ConvertToModel(cve *gostmodels.DebianCVE) *models.CveContent {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func checkPackageFixStatus(cve *gostmodels.DebianCVE) []models.PackageFixStatus {
|
||||
fixes := []models.PackageFixStatus{}
|
||||
for _, p := range cve.Package {
|
||||
for _, r := range p.Release {
|
||||
f := models.PackageFixStatus{Name: p.PackageName}
|
||||
|
||||
if r.Status == "open" {
|
||||
f.NotFixedYet = true
|
||||
} else {
|
||||
f.FixedIn = r.FixedVersion
|
||||
}
|
||||
|
||||
fixes = append(fixes, f)
|
||||
}
|
||||
}
|
||||
|
||||
return fixes
|
||||
}
|
||||
|
||||
71
gost/debian_test.go
Normal file
71
gost/debian_test.go
Normal file
@@ -0,0 +1,71 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
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 supported",
|
||||
args: args{
|
||||
major: "11",
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "12 is not supported yet",
|
||||
args: args{
|
||||
major: "12",
|
||||
},
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
154
gost/gost.go
154
gost/gost.go
@@ -1,104 +1,98 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Architect, Inc. Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package gost
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
cnf "github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/knqyf263/gost/db"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
"github.com/vulsio/gost/db"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/future-architect/vuls/constant"
|
||||
)
|
||||
|
||||
// DBDriver is a DB Driver
|
||||
type DBDriver struct {
|
||||
DB db.DB
|
||||
Cnf config.VulnDictInterface
|
||||
}
|
||||
|
||||
// Client is the interface of OVAL client.
|
||||
type Client interface {
|
||||
FillWithGost(db.DB, *models.ScanResult) (int, 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:
|
||||
return Debian{}
|
||||
case cnf.Windows:
|
||||
return Microsoft{}
|
||||
default:
|
||||
return Pseudo{}
|
||||
}
|
||||
DetectCVEs(*models.ScanResult, bool) (int, error)
|
||||
CloseDB() error
|
||||
}
|
||||
|
||||
// Base is a base struct
|
||||
type Base struct {
|
||||
family string
|
||||
DBDriver DBDriver
|
||||
}
|
||||
|
||||
// CheckHTTPHealth do health check
|
||||
func (b Base) CheckHTTPHealth() error {
|
||||
if !cnf.Conf.Gost.IsFetchViaHTTP() {
|
||||
// CloseDB close a DB connection
|
||||
func (b Base) CloseDB() error {
|
||||
if b.DBDriver.DB == nil {
|
||||
return nil
|
||||
}
|
||||
return b.DBDriver.DB.CloseDB()
|
||||
}
|
||||
|
||||
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 fmt.Errorf("Failed to connect to gost server. url: %s, errs: %v",
|
||||
url, errs)
|
||||
// FillCVEsWithRedHat fills CVE detailed with Red Hat Security
|
||||
func FillCVEsWithRedHat(r *models.ScanResult, cnf config.GostConf) error {
|
||||
db, locked, err := newGostDB(cnf)
|
||||
if locked {
|
||||
return xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
defer func() {
|
||||
if err := db.CloseDB(); err != nil {
|
||||
logging.Log.Errorf("Failed to close DB. err: %+v", err)
|
||||
}
|
||||
}()
|
||||
return RedHat{Base{DBDriver{DB: db, Cnf: &cnf}}}.fillCvesWithRedHatAPI(r)
|
||||
}
|
||||
|
||||
// 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
|
||||
// NewClient make Client by family
|
||||
func NewClient(cnf config.GostConf, family string) (Client, error) {
|
||||
db, locked, err := newGostDB(cnf)
|
||||
if locked {
|
||||
return nil, xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
driver := DBDriver{DB: db, Cnf: &cnf}
|
||||
|
||||
switch family {
|
||||
case constant.RedHat, constant.CentOS, constant.Rocky, constant.Alma:
|
||||
return RedHat{Base{DBDriver: driver}}, nil
|
||||
case constant.Debian, constant.Raspbian:
|
||||
return Debian{Base{DBDriver: driver}}, nil
|
||||
case constant.Ubuntu:
|
||||
return Ubuntu{Base{DBDriver: driver}}, nil
|
||||
case constant.Windows:
|
||||
return Microsoft{Base{DBDriver: driver}}, nil
|
||||
default:
|
||||
return Pseudo{Base{DBDriver: driver}}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// Pseudo is Gost client except for RedHat family and Debian
|
||||
type Pseudo struct {
|
||||
Base
|
||||
}
|
||||
|
||||
// FillWithGost fills cve information that has in Gost
|
||||
func (pse Pseudo) FillWithGost(driver db.DB, r *models.ScanResult) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func major(osVer string) (majorVersion string) {
|
||||
return strings.Split(osVer, ".")[0]
|
||||
// NewGostDB returns db client for Gost
|
||||
func newGostDB(cnf config.GostConf) (driver db.DB, locked bool, err error) {
|
||||
if cnf.IsFetchViaHTTP() {
|
||||
return nil, false, nil
|
||||
}
|
||||
path := cnf.GetURL()
|
||||
if cnf.GetType() == "sqlite3" {
|
||||
path = cnf.GetSQLite3Path()
|
||||
}
|
||||
if driver, locked, err = db.NewDB(cnf.GetType(), path, cnf.GetDebugSQL()); err != nil {
|
||||
if locked {
|
||||
return nil, true, xerrors.Errorf("gostDB is locked. err: %w", err)
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
return driver, false, nil
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package gost
|
||||
|
||||
import (
|
||||
@@ -5,7 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/future-architect/vuls/models"
|
||||
gostmodels "github.com/knqyf263/gost/models"
|
||||
gostmodels "github.com/vulsio/gost/models"
|
||||
)
|
||||
|
||||
func TestSetPackageStates(t *testing.T) {
|
||||
@@ -14,7 +17,7 @@ func TestSetPackageStates(t *testing.T) {
|
||||
installed models.Packages
|
||||
release string
|
||||
in models.VulnInfo
|
||||
out models.PackageStatuses
|
||||
out models.PackageFixStatuses
|
||||
}{
|
||||
|
||||
//0 one
|
||||
@@ -31,7 +34,7 @@ func TestSetPackageStates(t *testing.T) {
|
||||
},
|
||||
release: "7",
|
||||
in: models.VulnInfo{},
|
||||
out: []models.PackageStatus{
|
||||
out: []models.PackageFixStatus{
|
||||
{
|
||||
Name: "bouncycastle",
|
||||
FixState: "Will not fix",
|
||||
@@ -66,7 +69,7 @@ func TestSetPackageStates(t *testing.T) {
|
||||
},
|
||||
release: "7",
|
||||
in: models.VulnInfo{},
|
||||
out: []models.PackageStatus{
|
||||
out: []models.PackageFixStatus{
|
||||
{
|
||||
Name: "bouncycastle",
|
||||
FixState: "Will not fix",
|
||||
@@ -94,9 +97,9 @@ func TestSetPackageStates(t *testing.T) {
|
||||
},
|
||||
release: "7",
|
||||
in: models.VulnInfo{
|
||||
AffectedPackages: models.PackageStatuses{},
|
||||
AffectedPackages: models.PackageFixStatuses{},
|
||||
},
|
||||
out: models.PackageStatuses{},
|
||||
out: models.PackageFixStatuses{},
|
||||
},
|
||||
|
||||
//3 look only the same os release.
|
||||
@@ -113,9 +116,9 @@ func TestSetPackageStates(t *testing.T) {
|
||||
},
|
||||
release: "7",
|
||||
in: models.VulnInfo{
|
||||
AffectedPackages: models.PackageStatuses{},
|
||||
AffectedPackages: models.PackageFixStatuses{},
|
||||
},
|
||||
out: models.PackageStatuses{},
|
||||
out: models.PackageFixStatuses{},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,14 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Corporation , Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package gost
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/knqyf263/gost/db"
|
||||
gostmodels "github.com/knqyf263/gost/models"
|
||||
gostmodels "github.com/vulsio/gost/models"
|
||||
)
|
||||
|
||||
// Microsoft is Gost client for windows
|
||||
@@ -30,32 +16,36 @@ type Microsoft struct {
|
||||
Base
|
||||
}
|
||||
|
||||
// FillWithGost fills cve information that has in Gost
|
||||
func (ms Microsoft) FillWithGost(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
|
||||
if driver == nil {
|
||||
// DetectCVEs fills cve information that has in Gost
|
||||
func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) {
|
||||
if ms.DBDriver.DB == nil {
|
||||
return 0, nil
|
||||
}
|
||||
var cveIDs []string
|
||||
cveIDs := []string{}
|
||||
for cveID := range r.ScannedCves {
|
||||
cveIDs = append(cveIDs, cveID)
|
||||
}
|
||||
for cveID, msCve := range driver.GetMicrosoftMulti(cveIDs) {
|
||||
for cveID, msCve := range ms.DBDriver.DB.GetMicrosoftMulti(cveIDs) {
|
||||
if _, ok := r.ScannedCves[cveID]; !ok {
|
||||
continue
|
||||
}
|
||||
cveCont := ms.ConvertToModel(&msCve)
|
||||
cveCont, mitigations := ms.ConvertToModel(&msCve)
|
||||
v, _ := r.ScannedCves[cveID]
|
||||
if v.CveContents == nil {
|
||||
v.CveContents = models.CveContents{}
|
||||
}
|
||||
v.CveContents[models.Microsoft] = *cveCont
|
||||
v.CveContents[models.Microsoft] = []models.CveContent{*cveCont}
|
||||
v.Mitigations = append(v.Mitigations, mitigations...)
|
||||
r.ScannedCves[cveID] = v
|
||||
}
|
||||
return len(cveIDs), nil
|
||||
}
|
||||
|
||||
// ConvertToModel converts gost model to vuls model
|
||||
func (ms Microsoft) ConvertToModel(cve *gostmodels.MicrosoftCVE) *models.CveContent {
|
||||
func (ms Microsoft) ConvertToModel(cve *gostmodels.MicrosoftCVE) (*models.CveContent, []models.Mitigation) {
|
||||
sort.Slice(cve.ScoreSets, func(i, j int) bool {
|
||||
return cve.ScoreSets[i].Vector < cve.ScoreSets[j].Vector
|
||||
})
|
||||
v3score := 0.0
|
||||
var v3Vector string
|
||||
for _, scoreSet := range cve.ScoreSets {
|
||||
@@ -84,12 +74,11 @@ func (ms Microsoft) ConvertToModel(cve *gostmodels.MicrosoftCVE) *models.CveCont
|
||||
|
||||
option := map[string]string{}
|
||||
if 0 < len(cve.ExploitStatus) {
|
||||
// TODO: CVE-2020-0739
|
||||
// "exploit_status": "Publicly Disclosed:No;Exploited:No;Latest Software Release:Exploitation Less Likely;Older Software Release:Exploitation Less Likely;DOS:N/A",
|
||||
option["exploit"] = cve.ExploitStatus
|
||||
}
|
||||
if 0 < len(cve.Workaround) {
|
||||
option["workaround"] = cve.Workaround
|
||||
}
|
||||
var kbids []string
|
||||
kbids := []string{}
|
||||
for _, kbid := range cve.KBIDs {
|
||||
kbids = append(kbids, kbid.KBID)
|
||||
}
|
||||
@@ -97,6 +86,23 @@ func (ms Microsoft) ConvertToModel(cve *gostmodels.MicrosoftCVE) *models.CveCont
|
||||
option["kbids"] = strings.Join(kbids, ",")
|
||||
}
|
||||
|
||||
vendorURL := "https://msrc.microsoft.com/update-guide/vulnerability/" + cve.CveID
|
||||
mitigations := []models.Mitigation{}
|
||||
if cve.Mitigation != "" {
|
||||
mitigations = append(mitigations, models.Mitigation{
|
||||
CveContentType: models.Microsoft,
|
||||
Mitigation: cve.Mitigation,
|
||||
URL: vendorURL,
|
||||
})
|
||||
}
|
||||
if cve.Workaround != "" {
|
||||
mitigations = append(mitigations, models.Mitigation{
|
||||
CveContentType: models.Microsoft,
|
||||
Mitigation: cve.Workaround,
|
||||
URL: vendorURL,
|
||||
})
|
||||
}
|
||||
|
||||
return &models.CveContent{
|
||||
Type: models.Microsoft,
|
||||
CveID: cve.CveID,
|
||||
@@ -107,10 +113,9 @@ func (ms Microsoft) ConvertToModel(cve *gostmodels.MicrosoftCVE) *models.CveCont
|
||||
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,
|
||||
SourceLink: vendorURL,
|
||||
Optional: option,
|
||||
}
|
||||
}, mitigations
|
||||
}
|
||||
|
||||
18
gost/pseudo.go
Normal file
18
gost/pseudo.go
Normal file
@@ -0,0 +1,18 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package gost
|
||||
|
||||
import (
|
||||
"github.com/future-architect/vuls/models"
|
||||
)
|
||||
|
||||
// Pseudo is Gost client except for RedHat family and Debian
|
||||
type Pseudo struct {
|
||||
Base
|
||||
}
|
||||
|
||||
// DetectCVEs fills cve information that has in Gost
|
||||
func (pse Pseudo) DetectCVEs(_ *models.ScanResult, _ bool) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
252
gost/redhat.go
252
gost/redhat.go
@@ -1,19 +1,5 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Architect, Inc. Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package gost
|
||||
|
||||
@@ -25,8 +11,7 @@ import (
|
||||
"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"
|
||||
gostmodels "github.com/vulsio/gost/models"
|
||||
)
|
||||
|
||||
// RedHat is Gost client for RedHat family linux
|
||||
@@ -34,16 +19,45 @@ type RedHat struct {
|
||||
Base
|
||||
}
|
||||
|
||||
// FillWithGost fills cve information that has in Gost
|
||||
func (red RedHat) FillWithGost(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
|
||||
if nCVEs, err = red.fillUnfixed(driver, r); err != nil {
|
||||
return 0, err
|
||||
// DetectCVEs fills cve information that has in Gost
|
||||
func (red RedHat) DetectCVEs(r *models.ScanResult, ignoreWillNotFix bool) (nCVEs int, err error) {
|
||||
if red.DBDriver.Cnf.IsFetchViaHTTP() {
|
||||
prefix, _ := util.URLPathJoin(red.DBDriver.Cnf.GetURL(), "redhat", major(r.Release), "pkgs")
|
||||
responses, err := getAllUnfixedCvesViaHTTP(r, prefix)
|
||||
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 {
|
||||
if newly := red.setUnfixedCveToScanResult(&cve, r); newly {
|
||||
nCVEs++
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if red.DBDriver.DB == nil {
|
||||
return 0, nil
|
||||
}
|
||||
for _, pack := range r.Packages {
|
||||
// CVE-ID: RedhatCVE
|
||||
cves := red.DBDriver.DB.GetUnfixedCvesRedhat(major(r.Release), pack.Name, ignoreWillNotFix)
|
||||
for _, cve := range cves {
|
||||
if newly := red.setUnfixedCveToScanResult(&cve, r); newly {
|
||||
nCVEs++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nCVEs, red.fillFixed(driver, r)
|
||||
return nCVEs, nil
|
||||
}
|
||||
|
||||
func (red RedHat) fillFixed(driver db.DB, r *models.ScanResult) error {
|
||||
var cveIDs []string
|
||||
func (red RedHat) fillCvesWithRedHatAPI(r *models.ScanResult) error {
|
||||
cveIDs := []string{}
|
||||
for cveID, vuln := range r.ScannedCves {
|
||||
if _, ok := vuln.CveContents[models.RedHatAPI]; ok {
|
||||
continue
|
||||
@@ -51,9 +65,8 @@ func (red RedHat) fillFixed(driver db.DB, r *models.ScanResult) error {
|
||||
cveIDs = append(cveIDs, cveID)
|
||||
}
|
||||
|
||||
if config.Conf.Gost.IsFetchViaHTTP() {
|
||||
prefix, _ := util.URLPathJoin(config.Conf.Gost.URL,
|
||||
"redhat", "cves")
|
||||
if red.DBDriver.Cnf.IsFetchViaHTTP() {
|
||||
prefix, _ := util.URLPathJoin(config.Conf.Gost.URL, "redhat", "cves")
|
||||
responses, err := getCvesViaHTTP(cveIDs, prefix)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -66,132 +79,71 @@ func (red RedHat) fillFixed(driver db.DB, r *models.ScanResult) error {
|
||||
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
|
||||
red.setFixedCveToScanResult(&redCve, r)
|
||||
}
|
||||
} else {
|
||||
if driver == nil {
|
||||
if red.DBDriver.DB == nil {
|
||||
return nil
|
||||
}
|
||||
for cveID, redCve := range driver.GetRedhatMulti(cveIDs) {
|
||||
if redCve.ID == 0 {
|
||||
for _, redCve := range red.DBDriver.DB.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
|
||||
red.setFixedCveToScanResult(&redCve, r)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (red RedHat) fillUnfixed(driver db.DB, r *models.ScanResult) (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
|
||||
}
|
||||
}
|
||||
func (red RedHat) setFixedCveToScanResult(cve *gostmodels.RedhatCVE, r *models.ScanResult) {
|
||||
cveCont, mitigations := red.ConvertToModel(cve)
|
||||
v, ok := r.ScannedCves[cveCont.CveID]
|
||||
if ok {
|
||||
if v.CveContents == nil {
|
||||
v.CveContents = models.NewCveContents(*cveCont)
|
||||
} else {
|
||||
v.CveContents[models.RedHatAPI] = []models.CveContent{*cveCont}
|
||||
}
|
||||
} else {
|
||||
if driver == nil {
|
||||
return 0, nil
|
||||
}
|
||||
for _, pack := range r.Packages {
|
||||
// CVE-ID: RedhatCVE
|
||||
cves := map[string]gostmodels.RedhatCVE{}
|
||||
cves = driver.GetUnfixedCvesRedhat(major(r.Release), pack.Name)
|
||||
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
|
||||
}
|
||||
}
|
||||
v = models.VulnInfo{
|
||||
CveID: cveCont.CveID,
|
||||
CveContents: models.NewCveContents(*cveCont),
|
||||
Confidences: models.Confidences{models.RedHatAPIMatch},
|
||||
}
|
||||
}
|
||||
return nCVEs, nil
|
||||
v.Mitigations = append(v.Mitigations, mitigations...)
|
||||
r.ScannedCves[cveCont.CveID] = v
|
||||
}
|
||||
|
||||
func (red RedHat) mergePackageStates(v models.VulnInfo, ps []gostmodels.RedhatPackageState, installed models.Packages, release string) (pkgStats models.PackageStatuses) {
|
||||
func (red RedHat) setUnfixedCveToScanResult(cve *gostmodels.RedhatCVE, r *models.ScanResult) (newly bool) {
|
||||
cveCont, mitigations := 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] = []models.CveContent{*cveCont}
|
||||
}
|
||||
} else {
|
||||
v = models.VulnInfo{
|
||||
CveID: cveCont.CveID,
|
||||
CveContents: models.NewCveContents(*cveCont),
|
||||
Confidences: models.Confidences{models.RedHatAPIMatch},
|
||||
}
|
||||
newly = true
|
||||
}
|
||||
v.Mitigations = append(v.Mitigations, mitigations...)
|
||||
pkgStats := red.mergePackageStates(v,
|
||||
cve.PackageState, r.Packages, r.Release)
|
||||
if 0 < len(pkgStats) {
|
||||
v.AffectedPackages = pkgStats
|
||||
r.ScannedCves[cve.Name] = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
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 !=
|
||||
@@ -200,7 +152,8 @@ func (red RedHat) mergePackageStates(v models.VulnInfo, ps []gostmodels.RedhatPa
|
||||
}
|
||||
|
||||
if !(pstate.FixState == "Will not fix" ||
|
||||
pstate.FixState == "Fix deferred") {
|
||||
pstate.FixState == "Fix deferred" ||
|
||||
pstate.FixState == "Affected") {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -210,11 +163,11 @@ func (red RedHat) mergePackageStates(v models.VulnInfo, ps []gostmodels.RedhatPa
|
||||
|
||||
notFixedYet := false
|
||||
switch pstate.FixState {
|
||||
case "Will not fix", "Fix deferred":
|
||||
case "Will not fix", "Fix deferred", "Affected":
|
||||
notFixedYet = true
|
||||
}
|
||||
|
||||
pkgStats = pkgStats.Store(models.PackageStatus{
|
||||
pkgStats = pkgStats.Store(models.PackageFixStatus{
|
||||
Name: pstate.PackageName,
|
||||
FixState: pstate.FixState,
|
||||
NotFixedYet: notFixedYet,
|
||||
@@ -238,7 +191,7 @@ func (red RedHat) parseCwe(str string) (cwes []string) {
|
||||
}
|
||||
|
||||
// ConvertToModel converts gost model to vuls model
|
||||
func (red RedHat) ConvertToModel(cve *gostmodels.RedhatCVE) *models.CveContent {
|
||||
func (red RedHat) ConvertToModel(cve *gostmodels.RedhatCVE) (*models.CveContent, []models.Mitigation) {
|
||||
cwes := red.parseCwe(cve.Cwe)
|
||||
|
||||
details := []string{}
|
||||
@@ -264,11 +217,23 @@ func (red RedHat) ConvertToModel(cve *gostmodels.RedhatCVE) *models.CveContent {
|
||||
v3severity = cve.ThreatSeverity
|
||||
}
|
||||
|
||||
var refs []models.Reference
|
||||
refs := []models.Reference{}
|
||||
for _, r := range cve.References {
|
||||
refs = append(refs, models.Reference{Link: r.Reference})
|
||||
}
|
||||
|
||||
vendorURL := "https://access.redhat.com/security/cve/" + cve.Name
|
||||
mitigations := []models.Mitigation{}
|
||||
if cve.Mitigation != "" {
|
||||
mitigations = []models.Mitigation{
|
||||
{
|
||||
CveContentType: models.RedHatAPI,
|
||||
Mitigation: cve.Mitigation,
|
||||
URL: vendorURL,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return &models.CveContent{
|
||||
Type: models.RedHatAPI,
|
||||
CveID: cve.Name,
|
||||
@@ -282,8 +247,7 @@ func (red RedHat) ConvertToModel(cve *gostmodels.RedhatCVE) *models.CveContent {
|
||||
Cvss3Severity: v3severity,
|
||||
References: refs,
|
||||
CweIDs: cwes,
|
||||
Mitigation: cve.Mitigation,
|
||||
Published: cve.PublicDate,
|
||||
SourceLink: "https://access.redhat.com/security/cve/" + cve.Name,
|
||||
}
|
||||
SourceLink: vendorURL,
|
||||
}, mitigations
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package gost
|
||||
|
||||
import (
|
||||
|
||||
191
gost/ubuntu.go
Normal file
191
gost/ubuntu.go
Normal file
@@ -0,0 +1,191 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
|
||||
package gost
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
gostmodels "github.com/vulsio/gost/models"
|
||||
)
|
||||
|
||||
// Ubuntu is Gost client for Ubuntu
|
||||
type Ubuntu struct {
|
||||
Base
|
||||
}
|
||||
|
||||
func (ubu Ubuntu) supported(version string) bool {
|
||||
_, ok := map[string]string{
|
||||
"1404": "trusty",
|
||||
"1604": "xenial",
|
||||
"1804": "bionic",
|
||||
"2004": "focal",
|
||||
"2010": "groovy",
|
||||
"2104": "hirsute",
|
||||
}[version]
|
||||
return ok
|
||||
}
|
||||
|
||||
// DetectCVEs fills cve information that has in Gost
|
||||
func (ubu Ubuntu) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) {
|
||||
ubuReleaseVer := strings.Replace(r.Release, ".", "", 1)
|
||||
if !ubu.supported(ubuReleaseVer) {
|
||||
logging.Log.Warnf("Ubuntu %s is not supported yet", r.Release)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
linuxImage := "linux-image-" + r.RunningKernel.Release
|
||||
// Add linux and set the version of running kernel to search Gost.
|
||||
if r.Container.ContainerID == "" {
|
||||
newVer := ""
|
||||
if p, ok := r.Packages[linuxImage]; ok {
|
||||
newVer = p.NewVersion
|
||||
}
|
||||
r.Packages["linux"] = models.Package{
|
||||
Name: "linux",
|
||||
Version: r.RunningKernel.Version,
|
||||
NewVersion: newVer,
|
||||
}
|
||||
}
|
||||
|
||||
packCvesList := []packCves{}
|
||||
if ubu.DBDriver.Cnf.IsFetchViaHTTP() {
|
||||
url, _ := util.URLPathJoin(ubu.DBDriver.Cnf.GetURL(), "ubuntu", ubuReleaseVer, "pkgs")
|
||||
responses, err := getAllUnfixedCvesViaHTTP(r, url)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
for _, res := range responses {
|
||||
ubuCves := map[string]gostmodels.UbuntuCVE{}
|
||||
if err := json.Unmarshal([]byte(res.json), &ubuCves); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cves := []models.CveContent{}
|
||||
for _, ubucve := range ubuCves {
|
||||
cves = append(cves, *ubu.ConvertToModel(&ubucve))
|
||||
}
|
||||
packCvesList = append(packCvesList, packCves{
|
||||
packName: res.request.packName,
|
||||
isSrcPack: res.request.isSrcPack,
|
||||
cves: cves,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if ubu.DBDriver.DB == nil {
|
||||
return 0, nil
|
||||
}
|
||||
for _, pack := range r.Packages {
|
||||
ubuCves := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
|
||||
cves := []models.CveContent{}
|
||||
for _, ubucve := range ubuCves {
|
||||
cves = append(cves, *ubu.ConvertToModel(&ubucve))
|
||||
}
|
||||
packCvesList = append(packCvesList, packCves{
|
||||
packName: pack.Name,
|
||||
isSrcPack: false,
|
||||
cves: cves,
|
||||
})
|
||||
}
|
||||
|
||||
// SrcPack
|
||||
for _, pack := range r.SrcPackages {
|
||||
ubuCves := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
|
||||
cves := []models.CveContent{}
|
||||
for _, ubucve := range ubuCves {
|
||||
cves = append(cves, *ubu.ConvertToModel(&ubucve))
|
||||
}
|
||||
packCvesList = append(packCvesList, packCves{
|
||||
packName: pack.Name,
|
||||
isSrcPack: true,
|
||||
cves: cves,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
delete(r.Packages, "linux")
|
||||
|
||||
for _, p := range packCvesList {
|
||||
for _, cve := range p.cves {
|
||||
v, ok := r.ScannedCves[cve.CveID]
|
||||
if ok {
|
||||
if v.CveContents == nil {
|
||||
v.CveContents = models.NewCveContents(cve)
|
||||
} else {
|
||||
v.CveContents[models.UbuntuAPI] = []models.CveContent{cve}
|
||||
}
|
||||
} else {
|
||||
v = models.VulnInfo{
|
||||
CveID: cve.CveID,
|
||||
CveContents: models.NewCveContents(cve),
|
||||
Confidences: models.Confidences{models.UbuntuAPIMatch},
|
||||
}
|
||||
nCVEs++
|
||||
}
|
||||
|
||||
names := []string{}
|
||||
if p.isSrcPack {
|
||||
if srcPack, ok := r.SrcPackages[p.packName]; ok {
|
||||
for _, binName := range srcPack.BinaryNames {
|
||||
if _, ok := r.Packages[binName]; ok {
|
||||
names = append(names, binName)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if p.packName == "linux" {
|
||||
names = append(names, linuxImage)
|
||||
} else {
|
||||
names = append(names, p.packName)
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
v.AffectedPackages = v.AffectedPackages.Store(models.PackageFixStatus{
|
||||
Name: name,
|
||||
FixState: "open",
|
||||
NotFixedYet: true,
|
||||
})
|
||||
}
|
||||
r.ScannedCves[cve.CveID] = v
|
||||
}
|
||||
}
|
||||
return nCVEs, nil
|
||||
}
|
||||
|
||||
// ConvertToModel converts gost model to vuls model
|
||||
func (ubu Ubuntu) ConvertToModel(cve *gostmodels.UbuntuCVE) *models.CveContent {
|
||||
references := []models.Reference{}
|
||||
for _, r := range cve.References {
|
||||
if strings.Contains(r.Reference, "https://cve.mitre.org/cgi-bin/cvename.cgi?name=") {
|
||||
references = append(references, models.Reference{Source: "CVE", Link: r.Reference})
|
||||
} else {
|
||||
references = append(references, models.Reference{Link: r.Reference})
|
||||
}
|
||||
}
|
||||
|
||||
for _, b := range cve.Bugs {
|
||||
references = append(references, models.Reference{Source: "Bug", Link: b.Bug})
|
||||
}
|
||||
|
||||
for _, u := range cve.Upstreams {
|
||||
for _, upstreamLink := range u.UpstreamLinks {
|
||||
references = append(references, models.Reference{Source: "UPSTREAM", Link: upstreamLink.Link})
|
||||
}
|
||||
}
|
||||
|
||||
return &models.CveContent{
|
||||
Type: models.UbuntuAPI,
|
||||
CveID: cve.Candidate,
|
||||
Summary: cve.Description,
|
||||
Cvss2Severity: cve.Priority,
|
||||
Cvss3Severity: cve.Priority,
|
||||
SourceLink: "https://ubuntu.com/security/" + cve.Candidate,
|
||||
References: references,
|
||||
Published: cve.PublicDate,
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user