Compare commits

...

23 Commits

Author SHA1 Message Date
Kota Kanbe
7585f9d537 fix(report): fix cvedb-url, add -cvedb-type=http (#734)
* fix(report): fix cvedb-url, add -cvedb-type=http

* feat(report): support go-exploitdb server mode

* update deps

* implement tui

* fix server mode

* fix(tui): default value of cvedb-type to ""

* update deps
2018-11-16 21:22:18 +09:00
sadayuki-matsuno
76037cdf72 fix new cve contents (#735) 2018-11-15 13:43:06 +09:00
sadayuki-matsuno
98c5421edc fix exploit db (#733) 2018-11-12 17:36:53 +09:00
Kota Kanbe
e63fc7e3f5 fix(report): nil pointer in deep scan mode #728 (#732) 2018-11-10 12:36:12 +09:00
sadayuki-matsuno
6ed9cf3fb4 add scan mode (#731) 2018-11-05 15:35:50 +09:00
sadayuki-matsuno
9865eab2c0 Display exploit codes information for each detected CVE-IDs (#729)
* add exploit

* bug fix while loading config in TUI, display in format-full-text

* fix readme
2018-11-03 16:36:59 +09:00
Kota Kanbe
678e72a8b6 fix(gost): a bug of parseCwe (#726) 2018-10-29 21:21:20 +09:00
sadayuki-matsuno
ec41899089 check cve_contents init (#725)
check cve_contents init to avoid nil pointer
2018-10-29 16:27:54 +09:00
Harald Nordgren
b2d913cc21 Bump Go versions and use '.x' to always get latest patch versions (#724) 2018-10-29 16:26:20 +09:00
sadayuki-matsuno
bc86c24e6a update pkg (#723)
* update pkg

* change lint url
2018-10-18 13:37:17 +09:00
sadayuki-matsuno
87a77dd95c update pkgs (#720) 2018-10-10 17:43:26 +09:00
sadayuki-matsuno
e8188f3432 add ms gost (#718)
* add ms gost

* change gost branch
2018-10-05 12:45:26 +09:00
Kota Kanbe
50506be546 [WIP] feat(report): show repository of affected pkgs (#713)
feat(report): show repository of affected pkgs
2018-10-04 16:01:55 +09:00
Iskander (Alex) Sharipov
4ded028258 config: remove commented-out code from tomlloader (#714)
Signed-off-by: Iskander Sharipov <quasilyte@gmail.com>
2018-10-04 12:37:58 +09:00
Iskander (Alex) Sharipov
6da8b3c4a1 commands: simplify s[:] to s (#715)
If s is a slice, then `s[:]` is identical to just `s`.

Signed-off-by: Iskander Sharipov <quasilyte@gmail.com>
2018-10-04 12:37:31 +09:00
Iskander (Alex) Sharipov
d5c92cbcb3 report: simplify x = x <op> y to x <op>= y (#716)
Signed-off-by: Iskander Sharipov <quasilyte@gmail.com>
2018-10-04 12:35:02 +09:00
sadayuki-matsuno
ed5f98d6f0 change syslog pkg (#717) 2018-10-04 12:34:23 +09:00
Kota Kanbe
f854b8f908 fix(report): fix an error while loading cveDict.type in config.toml (#711) 2018-10-02 09:27:34 +09:00
Shigechika AIKAWA
de7a6159d4 remove table.SetHeaderColor codes (#709)
table.SetHeaderColor does not need in case of formatFullPlainText().
2018-09-25 10:31:22 +09:00
Kota Kanbe
6090a34037 fix(cpe): update deps to avoid parsing err of cpeNames (#708) 2018-09-13 13:42:04 +09:00
Kota Kanbe
f566745479 fix(config): a DB URL error 'does not validate as url' #705 (#706) 2018-09-11 09:19:24 +09:00
kota kanbe
153234b623 update readme 2018-08-29 22:39:05 +09:00
Kota Kanbe
ac510d21ff fix(scan): fix err msg when unable to connect via SSH (#702) 2018-08-29 10:48:32 +09:00
39 changed files with 1339 additions and 395 deletions

View File

@@ -1,7 +1,7 @@
language: go
go:
- "1.11"
- "1.11.x"
after_success:
- test -n "$TRAVIS_TAG" && curl -sL https://git.io/goreleaser | bash

View File

@@ -39,7 +39,7 @@ install: main.go dep pretest
lint:
@ go get -v github.com/golang/lint/golint
@ go get -v golang.org/x/lint/golint
golint $(PKGS)
vet:

363
Gopkg.lock generated
View File

@@ -2,18 +2,26 @@
[[projects]]
digest = "1:46ea9487304f4b3c787f54483ecb13a338d686dcd670db0ab1a112ed0ae2128e"
digest = "1:b92928b73320648b38c93cacb9082c0fe3f8ac3383ad9bd537eef62c380e0e7a"
name = "contrib.go.opencensus.io/exporter/ocagent"
packages = ["."]
pruneopts = "UT"
revision = "00af367e65149ff1f2f4b93bbfbb84fd9297170d"
version = "v0.2.0"
[[projects]]
digest = "1:386f6cd33248f04fc465df500e66d21892f0712e26c60d25b7ce3c678abaf2c0"
name = "github.com/Azure/azure-sdk-for-go"
packages = [
"storage",
"version",
]
pruneopts = "UT"
revision = "4e8cbbfb1aeab140cd0fa97fd16b64ee18c3ca6a"
version = "v19.1.0"
revision = "9699bdefa481d47c5c7638a1cc05d87ce53601fd"
version = "v22.2.2"
[[projects]]
digest = "1:327b9226c8ea5f1cd9952ba859bb7c335cab40fd8781c4a790ef259b0c5fbc40"
digest = "1:6b4743cf9d77747c1a772673333f8d6dfbfa93ffac858faae1333ffb7f0dfc4b"
name = "github.com/Azure/go-autorest"
packages = [
"autorest",
@@ -21,19 +29,28 @@
"autorest/azure",
"autorest/date",
"logger",
"tracing",
"version",
]
pruneopts = "UT"
revision = "39013ecb48eaf6ced3f4e3e1d95515140ce6b3cf"
version = "v10.15.2"
revision = "528b76fd0ebec0682f3e3da7c808cd472b999615"
version = "v11.2.7"
[[projects]]
digest = "1:b16fbfbcc20645cb419f78325bb2e85ec729b338e996a228124d68931a6f2a37"
digest = "1:9f3b30d9f8e0d7040f729b82dcbc8f0dead820a133b3147ce355fc451f32d761"
name = "github.com/BurntSushi/toml"
packages = ["."]
pruneopts = "UT"
revision = "b26d9c308763d68093482582cea63d69be07a0f0"
version = "v0.3.0"
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"
@@ -44,7 +61,7 @@
version = "v9"
[[projects]]
digest = "1:4f8b94c4cb403af4e7834e2a6455a25a5209dc61771b0d24a820ae9ae30f3f74"
digest = "1:176bfeb168867283ee97848f5e2cf9a0b6c9f395ea8c6d547907dfba845e0249"
name = "github.com/aws/aws-sdk-go"
packages = [
"aws",
@@ -64,6 +81,8 @@
"aws/request",
"aws/session",
"aws/signer/v4",
"internal/ini",
"internal/s3err",
"internal/sdkio",
"internal/sdkrand",
"internal/sdkuri",
@@ -80,8 +99,8 @@
"service/sts",
]
pruneopts = "UT"
revision = "4324bc9d8865bdb3e6aa86ec7772ca1272d2750e"
version = "v1.15.21"
revision = "64fc3d5c40fffc817c1cc1c1d89a6e482bf1120d"
version = "v1.15.77"
[[projects]]
digest = "1:0f98f59e9a2f4070d66f0c9c39561f68fcd1dc837b22a852d28d0003aebd1b1e"
@@ -99,6 +118,19 @@
revision = "2ea60e5f094469f9e65adb9cd103795b73ae743e"
version = "v2.0.0"
[[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"
@@ -132,15 +164,7 @@
version = "v1.4.7"
[[projects]]
digest = "1:5abd6a22805b1919f6a6bca0ae58b13cef1f3412812f38569978f43ef02743d4"
name = "github.com/go-ini/ini"
packages = ["."]
pruneopts = "UT"
revision = "5cf292cae48347c2490ac1a58fe36735fb78df7e"
version = "v1.38.2"
[[projects]]
digest = "1:ad9585b1b4361cbe8e7d8cc31af82ef5f597b9243909daa16f2c225b8af68c46"
digest = "1:34a9a60fade37f8009ed4a19e02924198aba3eabfcc120ee5c6002b7de17212d"
name = "github.com/go-redis/redis"
packages = [
".",
@@ -153,16 +177,16 @@
"internal/util",
]
pruneopts = "UT"
revision = "1614e579ed966441b8e0c3ccea1dd0fbbd93a6ae"
version = "v6.14.0"
revision = "b3d9bf10f6666b2ee5100a6f3f84f4caf3b4e37d"
version = "v6.14.2"
[[projects]]
digest = "1:adea5a94903eb4384abef30f3d878dc9ff6b6b5b0722da25b82e5169216dfb61"
digest = "1:ec6f9bf5e274c833c911923c9193867f3f18788c461f76f05f62bb1510e0ae65"
name = "github.com/go-sql-driver/mysql"
packages = ["."]
pruneopts = "UT"
revision = "d523deb1b23d913de5bdada721a6071e71283618"
version = "v1.4.0"
revision = "72cd26f257d44c1114970e19afddcd812016007e"
version = "v1.4.1"
[[projects]]
digest = "1:586ea76dbd0374d6fb649a91d70d652b7fe0ccffb8910a77468e7702e7901f3d"
@@ -172,21 +196,36 @@
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:b264547c40314ec7619d2cf264e2621953843be7242c140efe1e3119f93877f4"
digest = "1:df265b7f54410945dad5cf5979d91461b9fa7ff9b397ab58d2d577002a8a0e24"
name = "github.com/google/subcommands"
packages = ["."]
pruneopts = "UT"
revision = "5bae204cdfb2d92dcc333d56014bae6a2f6c58b1"
revision = "46f0354f63152e8801bb460d26f5b6c4c878efbb"
[[projects]]
digest = "1:cee8e8ac80df6373e7daa11baf1f98c1b6f7242c49ccae7e1ec34a971dc408d9"
digest = "1:7b5c6e2eeaa9ae5907c391a91c132abfd5c9e8a784a341b5625e750c67e6825d"
name = "github.com/gorilla/websocket"
packages = ["."]
pruneopts = "UT"
revision = "3ff3320c2a1756a3691521efc290b4701575147c"
version = "v1.3.0"
revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d"
version = "v1.4.0"
[[projects]]
branch = "master"
@@ -200,6 +239,14 @@
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:77395dd3847dac9c45118c668f5dab85aedf0163dc3b38aea6578c5cf0d502f9"
name = "github.com/hashicorp/go-version"
@@ -280,12 +327,12 @@
revision = "0b12d6b5"
[[projects]]
digest = "1:8e791db9ac7ec7eddd1f643be51d2dd66bb7093a92e86e3cbd22ddbeaad4d95b"
digest = "1:114ecad51af93a73ae6781fd0d0bc28e52b433c852b84ab4b4c109c15e6c6b6d"
name = "github.com/jroimartin/gocui"
packages = ["."]
pruneopts = "UT"
revision = "4e9ce9a8e26f2ef33dfe297dbdfca148733b6b9b"
version = "v0.3.0"
revision = "c055c87ae801372cd74a0839b972db4f7697ae5f"
version = "v0.4.0"
[[projects]]
digest = "1:16dd6b893b78a50564cdde1d9f7ea67224dece11bb0886bd882f1dc3dc1d440d"
@@ -324,7 +371,8 @@
revision = "74609b86c936dff800c69ec89fcf4bc52d5f13a4"
[[projects]]
digest = "1:7f4a6b4726da539e615256d19381f7c7326255f80ec19cdbeedcc4d9d57e1831"
branch = "master"
digest = "1:784bbde718d6f806578d929df8ad88a24817ca4fea5ce498165f46ff238d0deb"
name = "github.com/knqyf263/gost"
packages = [
"config",
@@ -333,11 +381,19 @@
"util",
]
pruneopts = "UT"
revision = "e926a00c01bead2152ea43026159ec5cee7ca998"
version = "v0.1.0"
revision = "920046ad61b30ed1d554140c85daaa9e3ed2ca9e"
[[projects]]
digest = "1:a0936d2be9f1dfa483fb8c2251453a9202dca2a374b1e42c7d75036a87d1c69d"
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:cdd699c1d929e96f96846789e99d5f019c15f714102a1bb108575d36789d577b"
name = "github.com/kotakanbe/go-cve-dictionary"
packages = [
"config",
@@ -346,8 +402,7 @@
"models",
]
pruneopts = "UT"
revision = "01c566055f7231f55f8551a2ae69569e0a4b9641"
version = "v0.2.0"
revision = "9549cd396c408c11f7d5cb6e4286dc8e7d9c6419"
[[projects]]
digest = "1:54d3c90db1164399906830313a6fce7770917d7e4a12da8f2d8693d18ff5ef27"
@@ -379,15 +434,15 @@
revision = "928f7356cb964637e2489a6ef37eee55181676c5"
[[projects]]
digest = "1:faee5b9f53eb1ae4eb04708c040c8c4dd685ce46509671e57a08520a15c54368"
digest = "1:01eb0269028d3c2e21b5b6cd9b1ba81bc4170ab293fcffa84e3aa3a6138a92e8"
name = "github.com/labstack/gommon"
packages = [
"color",
"log",
]
pruneopts = "UT"
revision = "d6898124de917583f5ff5592ef931d1dfe0ddc05"
version = "0.2.6"
revision = "7fd9f68ece0bcb1a905fac8f1549f0083f71c51b"
version = "v0.2.8"
[[projects]]
digest = "1:b18ffc558326ebaed3b4a175617f1e12ed4e3f53d6ebfe5ba372a3de16d22278"
@@ -426,12 +481,12 @@
version = "v0.0.9"
[[projects]]
digest = "1:d4d17353dbd05cb52a2a52b7fe1771883b682806f68db442b436294926bbfafb"
digest = "1:0981502f9816113c9c8c4ac301583841855c8cf4da8c72f696b3ebedf6d0e4e5"
name = "github.com/mattn/go-isatty"
packages = ["."]
pruneopts = "UT"
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
revision = "6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c"
version = "v0.0.4"
[[projects]]
digest = "1:cdb899c199f907ac9fb50495ec71212c95cb5b0e0a8ee0800da0238036091033"
@@ -442,12 +497,12 @@
version = "v0.0.3"
[[projects]]
digest = "1:3cafc6a5a1b8269605d9df4c6956d43d8011fc57f266ca6b9d04da6c09dee548"
digest = "1:4a49346ca45376a2bba679ca0e83bec949d780d4e927931317904bad482943ec"
name = "github.com/mattn/go-sqlite3"
packages = ["."]
pruneopts = "UT"
revision = "25ecb14adfc7543176f7d85291ec7dba82c6f7e4"
version = "v1.9.0"
revision = "c7c4067b79cc51e6dfdcef5c702e74b1e0fa7c75"
version = "v1.10.0"
[[projects]]
branch = "master"
@@ -466,44 +521,59 @@
version = "v1.0.0"
[[projects]]
digest = "1:645110e089152bd0f4a011a2648fbb0e4df5977be73ca605781157ac297f50c4"
digest = "1:53bc4cd4914cd7cd52139990d5170d6dc99067ae31c56530621b18b35fc30318"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
pruneopts = "UT"
revision = "fa473d140ef3c6adf42d6b391fe76707f1f243c8"
version = "v1.0.0"
revision = "3536a929edddb9a5b34bd6861dc4a9647cb459fe"
version = "v1.1.2"
[[projects]]
branch = "master"
digest = "1:7aefb397a53fc437c90f0fdb3e1419c751c5a3a165ced52325d5d797edf1aca6"
name = "github.com/moul/http2curl"
packages = ["."]
pruneopts = "UT"
revision = "9ac6cf4d929b2fa8fd2d2e6dec5bb0feb4f4911d"
[[projects]]
digest = "1:ace662a36243b5cdc2f71e654175dc192f903fafbf3411a95bc910c1cad53ce7"
name = "github.com/nlopes/slack"
packages = ["."]
pruneopts = "UT"
revision = "0db1d5eae1116bf7c8ed96c6749acfbf4daaec3e"
version = "v0.3.0"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:f335d800550786b6f51ddaedb9d1107a7a72f4a2195e5b039dd7c0e103e119bc"
digest = "1:f763c78fbcdc2e0938585b2c64ecd97761507af96f95a004d8cbb2feb23d3eaa"
name = "github.com/mozqnet/go-exploitdb"
packages = [
"db",
"models",
"util",
]
pruneopts = "UT"
revision = "48cac6d5786efbed25a10034dff534e5efd8617a"
[[projects]]
digest = "1:95d38d218bf2290987c6b0e885a9f0f2d3d3239235acaddca01c3fe36e5e5566"
name = "github.com/nlopes/slack"
packages = [
".",
"slackutilsx",
]
pruneopts = "UT"
revision = "b9033a72a20bf84563485e86a2adbea4bf265804"
version = "v0.4.0"
[[projects]]
branch = "master"
digest = "1:01d9e47830ef6077fb6f91033b0e83f324ad5966d11ed3daa4a5822ace876dab"
name = "github.com/nsf/termbox-go"
packages = ["."]
pruneopts = "UT"
revision = "b66b20ab708e289ff1eb3e218478302e6aec28ce"
revision = "60ab7e3d12ed91bc1b2486559c4b3a6b62297577"
[[projects]]
branch = "master"
digest = "1:4daa045e1e1f3e23f4b07db6880cdf9f259dab65312dfe244a878e6070faaf77"
digest = "1:abcdbf03ca6ca13d3697e2186edc1f33863bbdac2b3a44dfa39015e8903f7409"
name = "github.com/olekukonko/tablewriter"
packages = ["."]
pruneopts = "UT"
revision = "d4647c9c7a84d847478d890b816b7d8b62b0b279"
revision = "e6d60cf7ba1f42d86d54cdf5508611c4aafb3970"
version = "v0.0.1"
[[projects]]
digest = "1:d776f3e95774a8719f2e57fabbbb33103035fe072dcf6f1864f33abd17b753e5"
@@ -530,12 +600,12 @@
version = "v0.8.0"
[[projects]]
digest = "1:9a6f766efd8d5752adb7052aebb6e3d85255b31a8dff5e58ab4efa740ba9efa0"
digest = "1:1a23fdd843129ef761ffe7651bc5fe7c5b09fbe933e92783ab06cc11c37b7b37"
name = "github.com/rifflock/lfshook"
packages = ["."]
pruneopts = "UT"
revision = "bf539943797a1f34c1f502d07de419b5238ae6c6"
version = "v2.3"
revision = "b9218ef580f59a2e72dad1aa33d660150445d05a"
version = "v2.4"
[[projects]]
digest = "1:274f67cb6fed9588ea2521ecdac05a6d62a8c51c074c1fccc6a49a40ba80e925"
@@ -547,62 +617,62 @@
[[projects]]
branch = "master"
digest = "1:61ada1b10eccab5329199eaad8fc94048ed689969130010f592a6cc15f9afe39"
digest = "1:84b4f0801dc5a4137a0364b492b581fff859b3eca3979f6fca6e3d2c2e373cf5"
name = "github.com/sirupsen/logrus"
packages = ["."]
pruneopts = "UT"
revision = "49fbef4694fb220643e975c02c9547a1cda57c26"
revision = "44067abb194b1bc8b342e1f2120f8d3ea691b834"
[[projects]]
digest = "1:bd1ae00087d17c5a748660b8e89e1043e1e5479d0fea743352cda2f8dd8c4f84"
digest = "1:6a4a11ba764a56d2758899ec6f3848d24698d48442ebce85ee7a3f63284526cd"
name = "github.com/spf13/afero"
packages = [
".",
"mem",
]
pruneopts = "UT"
revision = "787d034dfe70e44075ccc060d346146ef53270ad"
version = "v1.1.1"
revision = "d40851caa0d747393da1ffb28f7f9d8b4eeffebd"
version = "v1.1.2"
[[projects]]
digest = "1:516e71bed754268937f57d4ecb190e01958452336fa73dbac880894164e91c1f"
digest = "1:08d65904057412fc0270fc4812a1c90c594186819243160dc779a402d4b6d0bc"
name = "github.com/spf13/cast"
packages = ["."]
pruneopts = "UT"
revision = "8965335b8c7107321228e3e3702cab9832751bac"
version = "v1.2.0"
revision = "8c9545af88b134710ab1cd196795e7f2388358d7"
version = "v1.3.0"
[[projects]]
branch = "master"
digest = "1:8a020f916b23ff574845789daee6818daf8d25a4852419aae3f0b12378ba432a"
digest = "1:68ea4e23713989dc20b1bded5d9da2c5f9be14ff9885beef481848edd18c26cb"
name = "github.com/spf13/jwalterweatherman"
packages = ["."]
pruneopts = "UT"
revision = "14d3d4c518341bea657dd8a226f5121c0ff8c9f2"
revision = "4a4406e478ca629068e7768fc33f3f044173c0a6"
version = "v1.0.0"
[[projects]]
digest = "1:dab83a1bbc7ad3d7a6ba1a1cc1760f25ac38cdf7d96a5cdd55cd915a4f5ceaf9"
digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2"
name = "github.com/spf13/pflag"
packages = ["."]
pruneopts = "UT"
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
version = "v1.0.2"
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
version = "v1.0.3"
[[projects]]
digest = "1:4fc8a61287ccfb4286e1ca5ad2ce3b0b301d746053bf44ac38cf34e40ae10372"
digest = "1:214775c11fd26da94a100111a62daa25339198a4f9c57cb4aab352da889f5b93"
name = "github.com/spf13/viper"
packages = ["."]
pruneopts = "UT"
revision = "907c19d40d9a6c9bb55f040ff4ae45271a4754b9"
version = "v1.1.0"
revision = "2c12c60302a5a0e62ee102ca9bc996277c2f64f5"
version = "v1.2.1"
[[projects]]
branch = "master"
digest = "1:c468422f334a6b46a19448ad59aaffdfc0a36b08fdcc1c749a0b29b6453d7e59"
name = "github.com/valyala/bytebufferpool"
packages = ["."]
pruneopts = "UT"
revision = "e746df99fe4a3986f4d4f79e13c1e0117ce9c2f7"
version = "v1.0.0"
[[projects]]
branch = "master"
@@ -620,9 +690,33 @@
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:6019f7d49498f02cd589d41db388e11470de1f218a0a534c52353788684d8cd9"
digest = "1:29bbd24a92d33c22d209247c0d0e42caeb90ff17802d9c64faaa79299213cf0a"
name = "golang.org/x/crypto"
packages = [
"curve25519",
@@ -636,30 +730,43 @@
"ssh/terminal",
]
pruneopts = "UT"
revision = "614d502a4dac94afa3a6ce146bd1736da82514c6"
revision = "3d3f9f413869b949e48070b5bc593aa22cc2b8f2"
[[projects]]
branch = "master"
digest = "1:357e8a9010dc590929a02bc5602c058acea216e4c46089755e618a5a59789604"
digest = "1:025c818c2258943954db285ddf18924b51f7ab6dd567b070299dc56c05bea037"
name = "golang.org/x/net"
packages = [
"context",
"http/httpguts",
"http2",
"http2/hpack",
"idna",
"internal/timeseries",
"publicsuffix",
"trace",
]
pruneopts = "UT"
revision = "8a410e7b638dca158bf9e766925842f6651ff828"
revision = "adae6a3d119ae4890b46832a2e88a95adc62b8e7"
[[projects]]
branch = "master"
digest = "1:0dafafed83f125cdc945a014b2dec15e5b5d8cd2d77a2d1e3763120b08ab381b"
digest = "1:5e4d81c50cffcb124b899e4f3eabec3930c73532f0096c27f94476728ba03028"
name = "golang.org/x/sync"
packages = ["semaphore"]
pruneopts = "UT"
revision = "42b317875d0fa942474b76e1b46a6060d720ae6e"
[[projects]]
branch = "master"
digest = "1:6a875550c3b582f6c2d7e2ce44aba792511f00016d7c46b0a4fb26f730ef3058"
name = "golang.org/x/sys"
packages = [
"unix",
"windows",
]
pruneopts = "UT"
revision = "4910a1d54f876d7b22162a85f4d066d3ee649450"
revision = "66b7b1311ac80bbafcd2daeef9a5e6e2cd1e2399"
[[projects]]
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
@@ -684,13 +791,64 @@
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
branch = "master"
digest = "1:5f003878aabe31d7f6b842d4de32b41c46c214bb629bb485387dbcce1edf5643"
name = "google.golang.org/api"
packages = ["support/bundler"]
pruneopts = "UT"
revision = "83a9d304b1e613fc253e1e2710778642fe81af53"
[[projects]]
digest = "1:c25289f43ac4a68d88b02245742347c94f1e108c534dda442188015ff80669b3"
name = "google.golang.org/appengine"
packages = ["cloudsql"]
pruneopts = "UT"
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
version = "v1.1.0"
revision = "4a4468ece617fc8205e99368fa2200e9d1fad421"
version = "v1.3.0"
[[projects]]
branch = "master"
digest = "1:56b0bca90b7e5d1facf5fbdacba23e4e0ce069d25381b8e2f70ef1e7ebfb9c1a"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
pruneopts = "UT"
revision = "b5d43981345bdb2c233eb4bf3277847b48c6fdc6"
[[projects]]
digest = "1:c3ad9841823db6da420a5625b367913b4ff54bbe60e8e3c98bd20e243e62e2d2"
name = "google.golang.org/grpc"
packages = [
".",
"balancer",
"balancer/base",
"balancer/roundrobin",
"codes",
"connectivity",
"credentials",
"encoding",
"encoding/proto",
"grpclog",
"internal",
"internal/backoff",
"internal/channelz",
"internal/envconfig",
"internal/grpcrand",
"internal/transport",
"keepalive",
"metadata",
"naming",
"peer",
"resolver",
"resolver/dns",
"resolver/passthrough",
"stats",
"status",
"tap",
]
pruneopts = "UT"
revision = "2e463a05d100327ca47ac218281906921038fd95"
version = "v1.16.0"
[[projects]]
digest = "1:e626376fab8608a972d47e91b3c1bbbddaecaf1d42b82be6dcc52d10a7557893"
@@ -701,12 +859,12 @@
version = "v1.1.1"
[[projects]]
digest = "1:d8cd4f14785b5ae65100524a29ebba8b9dfc5401020fe7504f80b438bb8e8e0d"
digest = "1:50ec2f81389fbc7a1e496e1d1dc07adfe080fd15e015e9ba0e08ddaf1d4635ef"
name = "gopkg.in/cheggaaa/pb.v1"
packages = ["."]
pruneopts = "UT"
revision = "2af8bbdea9e99e83b3ac400d8f6b6d1b8cbbf338"
version = "v1.0.25"
revision = "007b75a044e968336a69a6c0c617251ab62ac14c"
version = "v1.0.26"
[[projects]]
digest = "1:256938e7d43c73bd5e7bb97dd281d1ebe294b2928403ee1fbec96249915d1150"
@@ -733,12 +891,12 @@
version = "v0.0.9"
[[projects]]
digest = "1:d4d17353dbd05cb52a2a52b7fe1771883b682806f68db442b436294926bbfafb"
digest = "1:0981502f9816113c9c8c4ac301583841855c8cf4da8c72f696b3ebedf6d0e4e5"
name = "gopkg.in/mattn/go-isatty.v0"
packages = ["."]
pruneopts = "UT"
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
revision = "6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c"
version = "v0.0.4"
[[projects]]
digest = "1:cdb899c199f907ac9fb50495ec71212c95cb5b0e0a8ee0800da0238036091033"
@@ -762,6 +920,7 @@
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",
@@ -791,6 +950,8 @@
"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",

View File

@@ -24,6 +24,18 @@
# 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

110
README.md
View File

@@ -45,50 +45,78 @@ Vuls is a tool created to solve the problems listed above. It has the following
# Main Features
- Scan for any vulnerabilities in Linux/FreeBSD Server
- Supports Alpine, Ubuntu, Debian, CentOS, Amazon Linux, RHEL, Oracle Linux, SUSE Enterprise Linux and Raspbian, FreeBSD
- Cloud, on-premise, Docker
- High quality scan
- Vuls uses Multiple vulnerability databases
- [NVD](https://nvd.nist.gov/)
- [JVN(Japanese)](http://jvndb.jvn.jp/apis/myjvn/)
- [RedHat](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/)
- RHSA/ALAS/ELSA/FreeBSD-SA
- Changelog
- Fast scan and Deep scan
- Fast Scan
- Scan without root privilege
- Scan with No internet access. (RedHat, CentOS, OracleLinux, Ubuntu and Debian)
- Almost no load on the scan target server
- Deep Scan
- Scan with root privilege
- Detect processes affected by update using yum-ps (RedHat, CentOS, OracleLinux and Amazon Linux)
- 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 and Local scan
- Remote Scan
- User is required to only setup one machine that is connected to other target servers via SSH
- Local Scan
- 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
- 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 middleware that are not included in OS package management
- Scan middleware, programming language libraries and framework for vulnerability
- Support software registered in CPE
## 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
## High quality scan
Vuls uses Multiple vulnerability databases
- [NVD](https://nvd.nist.gov/)
- [JVN(Japanese)](http://jvndb.jvn.jp/apis/myjvn/)
- OVAL
- [RedHat](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/)
- Changelog
## Fast scan and Deep scan
[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)
[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 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)
[Deep Scan](https://vuls.io/docs/en/architecture-deep-scan.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 and Local scan](https://vuls.io/docs/en/architecture-remote-local.html)
[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)
- 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
- 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 middleware that are not included in OS package management](https://vuls.io/docs/en/usage-scan-non-os-packages.html)
- Scan middleware, programming language libraries and framework for vulnerability
- Support software registered in CPE
## 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.
- 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 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)).

View File

@@ -91,24 +91,27 @@ func (p *DiscoverCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface
func printConfigToml(ips []string) (err error) {
const tomlTemplate = `
# TODO Doc Link
# https://vuls.io/docs/en/usage-settings.html
[cveDict]
type = "sqlite3"
sqlite3Path = "/path/to/cve.sqlite3"
#url = ""
# TODO Doc Link
[ovalDict]
type = "sqlite3"
sqlite3Path = "/path/to/oval.sqlite3"
#url = ""
# TODO Doc Link
[gost]
type = "sqlite3"
sqlite3Path = "/path/to/gost.sqlite3"
#url = ""
[exploit]
type = "sqlite3"
sqlite3Path = "/path/to/go-exploitdb.sqlite3"
#url = ""
# https://vuls.io/docs/en/usage-settings.html#slack-section
#[slack]
#hookURL = "https://hooks.slack.com/services/abc123/defghijklmnopqrstuvwxyz"

View File

@@ -24,6 +24,7 @@ import (
"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"
@@ -36,11 +37,12 @@ import (
// ReportCmd is subcommand for reporting
type ReportCmd struct {
configPath string
cvelDict c.GoCveDictConf
ovalDict c.GovalDictConf
gostConf c.GostConf
httpConf c.HTTPConf
configPath string
cveDict c.GoCveDictConf
ovalDict c.GovalDictConf
gostConf c.GostConf
exploitConf c.ExploitConf
httpConf c.HTTPConf
}
// Name return subcommand name
@@ -84,15 +86,18 @@ func (*ReportCmd) Usage() string {
[-debug]
[-debug-sql]
[-pipe]
[-cvedb-type=sqlite3|mysql|postgres|redis]
[-cvedb-path=/path/to/cve.sqlite3]
[-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]
[-ovaldb-path=/path/to/oval.sqlite3]
[-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]
[-gostdb-path=/path/to/gost.sqlite3]
[-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]
@@ -165,24 +170,30 @@ func (p *ReportCmd) SetFlags(f *flag.FlagSet) {
"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.cvelDict.Type, "cvedb-type", "sqlite3",
"DB type of go-cve-dictionary (sqlite3, mysql, postgres or redis)")
f.StringVar(&p.cvelDict.SQLite3Path, "cvedb-sqlite3-path", "", "/path/to/sqlite3")
f.StringVar(&p.cvelDict.URL, "cvedb-url", "",
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 or redis)")
"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 or redis)")
"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")
}
@@ -197,9 +208,10 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
return subcommands.ExitUsageError
}
c.Conf.CveDict.Overwrite(p.cvelDict)
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
@@ -338,31 +350,21 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
return subcommands.ExitUsageError
}
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-path option instead of -cvedb-url")
return subcommands.ExitFailure
}
if c.Conf.CveDict.URL != "" {
util.Log.Infof("cve-dictionary: %s", c.Conf.CveDict.URL)
} else {
if c.Conf.CveDict.Type == "sqlite3" {
util.Log.Infof("cve-dictionary: %s", c.Conf.CveDict.SQLite3Path)
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 != "" {
util.Log.Infof("oval-dictionary: %s", 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-path option instead of -ovaldb-url")
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
}
} else {
if c.Conf.OvalDict.Type == "sqlite3" {
util.Log.Infof("oval-dictionary: %s", c.Conf.OvalDict.SQLite3Path)
}
}
if c.Conf.Gost.URL != "" {
@@ -370,18 +372,24 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
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-path option instead of -gostdb-url")
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
}
} else {
if c.Conf.Gost.Type == "sqlite3" {
util.Log.Infof("gost: %s", c.Conf.Gost.SQLite3Path)
}
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 {

View File

@@ -28,6 +28,8 @@ import (
// "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"
@@ -38,11 +40,12 @@ import (
// ServerCmd is subcommand for server
type ServerCmd struct {
configPath string
listen string
cvelDict c.GoCveDictConf
ovalDict c.GovalDictConf
gostConf c.GostConf
configPath string
listen string
cveDict c.GoCveDictConf
ovalDict c.GovalDictConf
gostConf c.GostConf
exploitConf c.ExploitConf
}
// Name return subcommand name
@@ -59,36 +62,26 @@ func (*ServerCmd) Usage() string {
[-config=/path/to/config.toml]
[-log-dir=/path/to/log]
[-cvss-over=7]
[-diff]
[-ignore-unscored-cves]
[-ignore-unfixed]
[-to-email]
[-to-slack]
[-to-stride]
[-to-hipchat]
[-to-chatwork]
[-to-localfile]
[-to-s3]
[-to-azure-blob]
[-format-json]
[-format-xml]
[-format-one-email]
[-format-one-line-text]
[-format-list]
[-format-full-text]
[-http-proxy=http://192.168.0.1:8080]
[-debug]
[-debug-sql]
[-listen=localhost:5515]
[-cvedb-type=sqlite3|mysql|postgres|redis]
[-cvedb-path=/path/to/cve.sqlite3]
[-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]
[-ovaldb-path=/path/to/oval.sqlite3]
[-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]
[-gostdb-path=/path/to/gost.sqlite3]
[-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]
`
@@ -128,23 +121,29 @@ func (p *ServerCmd) SetFlags(f *flag.FlagSet) {
f.StringVar(&p.listen, "listen", "localhost:5515",
"host:port (default: localhost:5515)")
f.StringVar(&p.cvelDict.Type, "cvedb-type", "sqlite3",
"DB type of go-cve-dictionary (sqlite3, mysql, postgres or redis)")
f.StringVar(&p.cvelDict.SQLite3Path, "cvedb-path", "", "/path/to/sqlite3")
f.StringVar(&p.cvelDict.URL, "cvedb-url", "",
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 or redis)")
f.StringVar(&p.ovalDict.SQLite3Path, "ovaldb-path", "", "/path/to/sqlite3")
"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 or redis)")
f.StringVar(&p.gostConf.SQLite3Path, "gostdb-path", "", "/path/to/sqlite3")
"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
@@ -152,39 +151,59 @@ func (p *ServerCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
util.Log = util.NewCustomLogger(c.ServerInfo{})
cvelog.SetLogger(c.Conf.LogDir, false, c.Conf.Debug, false)
c.Conf.CveDict.Overwrite(p.cvelDict)
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
}
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 Servering or run with -cvedb-path option")
return subcommands.ExitFailure
util.Log.Info("Validating db config...")
if !c.Conf.ValidateOnReportDB() {
return subcommands.ExitUsageError
}
if c.Conf.CveDict.URL != "" {
util.Log.Infof("cve-dictionary: %s", c.Conf.CveDict.URL)
} else {
if c.Conf.CveDict.Type == "sqlite3" {
util.Log.Infof("cve-dictionary: %s", c.Conf.CveDict.SQLite3Path)
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 != "" {
util.Log.Infof("oval-dictionary: %s", 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 Servering or run with -ovaldb-path option")
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
}
} else {
if c.Conf.OvalDict.Type == "sqlite3" {
util.Log.Infof("oval-dictionary: %s", c.Conf.OvalDict.SQLite3Path)
}
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
}
}
@@ -192,6 +211,7 @@ func (p *ServerCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
CveDictCnf: c.Conf.CveDict,
OvalDictCnf: c.Conf.OvalDict,
GostCnf: c.Conf.Gost,
ExploitCnf: c.Conf.Exploit,
DebugSQL: c.Conf.DebugSQL,
})
if locked {

View File

@@ -24,7 +24,10 @@ import (
"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"
@@ -33,10 +36,11 @@ import (
// TuiCmd is Subcommand of host discovery mode
type TuiCmd struct {
configPath string
cvelDict c.GoCveDictConf
ovalDict c.GovalDictConf
gostConf c.GostConf
configPath string
cveDict c.GoCveDictConf
ovalDict c.GovalDictConf
gostConf c.GostConf
exploitConf c.ExploitConf
}
// Name return subcommand name
@@ -60,15 +64,18 @@ func (*TuiCmd) Usage() string {
[-debug]
[-debug-sql]
[-pipe]
[-cvedb-type=sqlite3|mysql|postgres|redis]
[-cvedb-path=/path/to/cve.sqlite3]
[-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]
[-ovaldb-path=/path/to/oval.sqlite3]
[-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]
[-gostdb-path=/path/to/gost.sqlite3]
[-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]
`
}
@@ -107,10 +114,10 @@ func (p *TuiCmd) SetFlags(f *flag.FlagSet) {
f.BoolVar(&c.Conf.Pipe, "pipe", false, "Use stdin via PIPE")
f.StringVar(&p.cvelDict.Type, "cvedb-type", "sqlite3",
f.StringVar(&p.cveDict.Type, "cvedb-type", "",
"DB type of go-cve-dictionary (sqlite3, mysql, postgres or redis)")
f.StringVar(&p.cvelDict.SQLite3Path, "cvedb-path", "", "/path/to/sqlite3")
f.StringVar(&p.cvelDict.URL, "cvedb-url", "",
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", "",
@@ -124,6 +131,13 @@ func (p *TuiCmd) SetFlags(f *flag.FlagSet) {
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
@@ -139,14 +153,10 @@ func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) s
return subcommands.ExitUsageError
}
c.Conf.CveDict.Overwrite(p.cvelDict)
c.Conf.CveDict.Overwrite(p.cveDict)
c.Conf.OvalDict.Overwrite(p.ovalDict)
c.Conf.Gost.Overwrite(p.gostConf)
util.Log.Info("Validating config...")
if !c.Conf.ValidateOnTui() {
return subcommands.ExitUsageError
}
c.Conf.Exploit.Overwrite(p.exploitConf)
var dir string
var err error
@@ -159,6 +169,12 @@ func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) s
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)
@@ -166,10 +182,51 @@ func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) s
}
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 {

View File

@@ -34,7 +34,7 @@ func getPasswd(prompt string) (string, error) {
return "", fmt.Errorf("Failed to read password")
}
if 0 < len(pass) {
return string(pass[:]), nil
return string(pass), nil
}
}

View File

@@ -20,19 +20,20 @@ package config
import (
"errors"
"fmt"
"log/syslog"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
syslog "github.com/RackSec/srslog"
valid "github.com/asaskevich/govalidator"
log "github.com/sirupsen/logrus"
)
// Version of Vuls
var Version = "0.5.0"
var Version = "0.6.1"
// Revision of Git
var Revision string
@@ -121,6 +122,7 @@ type Config struct {
CveDict GoCveDictConf `json:"cveDict"`
OvalDict GovalDictConf `json:"ovalDict"`
Gost GostConf `json:"gost"`
Exploit ExploitConf `json:"exploit"`
Slack SlackConf `json:"-"`
EMail SMTPConf `json:"-"`
@@ -234,6 +236,14 @@ func (c Config) ValidateOnReportDB() bool {
errs = append(errs, err)
}
if err := validateDB("gostdb", c.Gost.Type, c.Gost.SQLite3Path, c.Gost.URL); err != nil {
errs = append(errs, err)
}
if err := validateDB("exploitdb", c.Exploit.Type, c.Exploit.SQLite3Path, c.Exploit.URL); err != nil {
errs = append(errs, err)
}
for _, err := range errs {
log.Error(err)
}
@@ -326,39 +336,42 @@ func (c Config) ValidateOnTui() bool {
// validateDB validates configuration
// dictionaryDB name is 'cvedb' or 'ovaldb'
func validateDB(dictionaryDBName, dbType, dbPath, dbURL string) error {
log.Infof("-%s-type: %s, -%s-url: %s, -%s-path: %s",
dictionaryDBName, dbType, dictionaryDBName, dbURL, dictionaryDBName, dbPath)
switch dbType {
case "sqlite3":
if dbURL != "" {
return fmt.Errorf("To use SQLite3, specify -%s-type=sqlite3 and -%s-path. To use as http server mode, specify -%s-type=http and -%s-url",
dictionaryDBName, dictionaryDBName, dictionaryDBName, dictionaryDBName)
}
if ok, _ := valid.IsFilePath(dbPath); !ok {
return fmt.Errorf(
"SQLite3 DB path (%s) must be a *Absolute* file path. -%s-path: %s",
dictionaryDBName,
dictionaryDBName,
dbPath)
return fmt.Errorf("SQLite3 path must be a *Absolute* file path. -%s-path: %s",
dictionaryDBName, dbPath)
}
case "mysql":
if dbURL == "" {
return fmt.Errorf(
`MySQL connection string is needed. -%s-url="user:pass@tcp(localhost:3306)/dbname"`,
return fmt.Errorf(`MySQL connection string is needed. -%s-url="user:pass@tcp(localhost:3306)/dbname"`,
dictionaryDBName)
}
case "postgres":
if dbURL == "" {
return fmt.Errorf(
`PostgreSQL connection string is needed. -%s-url="host=myhost user=user dbname=dbname sslmode=disable password=password"`,
return fmt.Errorf(`PostgreSQL connection string is needed. -%s-url="host=myhost user=user dbname=dbname sslmode=disable password=password"`,
dictionaryDBName)
}
case "redis":
if dbURL == "" {
return fmt.Errorf(
`Redis connection string is needed. -%s-url="redis://localhost/0"`,
return fmt.Errorf(`Redis connection string is needed. -%s-url="redis://localhost/0"`,
dictionaryDBName)
}
case "http":
if dbURL == "" {
return fmt.Errorf(`URL is needed. -%s-url="http://localhost:1323"`,
dictionaryDBName)
}
default:
return fmt.Errorf(
"%s type must be either 'sqlite3', 'mysql', 'postgres' or 'redis'. -%s-type: %s",
dictionaryDBName,
dictionaryDBName,
dbType)
return fmt.Errorf("%s type must be either 'sqlite3', 'mysql', 'postgres', 'redis' or 'http'. -%s-type: %s",
dictionaryDBName, dictionaryDBName, dbType)
}
return nil
}
@@ -734,7 +747,7 @@ type GoCveDictConf struct {
Type string
// http://cve-dictionary.com:1323 or DB connection string
URL string `valid:"url" json:"-"`
URL string `json:"-"`
// /path/to/cve.sqlite3
SQLite3Path string `json:"-"`
@@ -781,6 +794,11 @@ func (cnf *GoCveDictConf) Overwrite(cmdOpt GoCveDictConf) {
cnf.setDefault()
}
// IsFetchViaHTTP returns wether fetch via http
func (cnf *GoCveDictConf) IsFetchViaHTTP() bool {
return Conf.CveDict.Type == "http"
}
// GovalDictConf is goval-dictionary config
type GovalDictConf struct {
@@ -788,7 +806,7 @@ type GovalDictConf struct {
Type string
// http://goval-dictionary.com:1324 or DB connection string
URL string `valid:"url" json:"-"`
URL string `json:"-"`
// /path/to/oval.sqlite3
SQLite3Path string `json:"-"`
@@ -835,13 +853,18 @@ func (cnf *GovalDictConf) Overwrite(cmdOpt GovalDictConf) {
cnf.setDefault()
}
// IsFetchViaHTTP returns wether fetch via http
func (cnf *GovalDictConf) IsFetchViaHTTP() bool {
return Conf.OvalDict.Type == "http"
}
// GostConf is gost config
type GostConf struct {
// DB type for gost dictionary (sqlite3, mysql, postgres or redis)
Type string
// http://gost-dictionary.com:1324 or DB connection string
URL string `valid:"url" json:"-"`
URL string `json:"-"`
// /path/to/gost.sqlite3
SQLite3Path string `json:"-"`
@@ -888,6 +911,69 @@ func (cnf *GostConf) Overwrite(cmdOpt GostConf) {
cnf.setDefault()
}
// IsFetchViaHTTP returns wether fetch via http
func (cnf *GostConf) IsFetchViaHTTP() bool {
return Conf.Gost.Type == "http"
}
// ExploitConf is exploit config
type ExploitConf struct {
// DB type for exploit dictionary (sqlite3, mysql, postgres or redis)
Type string
// http://exploit-dictionary.com:1324 or DB connection string
URL string `json:"-"`
// /path/to/exploit.sqlite3
SQLite3Path string `json:"-"`
}
func (cnf *ExploitConf) setDefault() {
if cnf.Type == "" {
cnf.Type = "sqlite3"
}
if cnf.URL == "" && cnf.SQLite3Path == "" {
wd, _ := os.Getwd()
cnf.SQLite3Path = filepath.Join(wd, "go-exploitdb.sqlite3")
}
}
const exploitDBType = "EXPLOITDB_TYPE"
const exploitDBURL = "EXPLOITDB_URL"
const exploitDBPATH = "EXPLOITDB_SQLITE3_PATH"
// Overwrite set options with the following priority.
// 1. Command line option
// 2. Environment variable
// 3. config.toml
func (cnf *ExploitConf) Overwrite(cmdOpt ExploitConf) {
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)
}
if cmdOpt.Type != "" {
cnf.Type = cmdOpt.Type
}
if cmdOpt.URL != "" {
cnf.URL = cmdOpt.URL
}
if cmdOpt.SQLite3Path != "" {
cnf.SQLite3Path = cmdOpt.SQLite3Path
}
cnf.setDefault()
}
// IsFetchViaHTTP returns wether fetch via http
func (cnf *ExploitConf) IsFetchViaHTTP() bool {
return Conf.Exploit.Type == "http"
}
// AWS is aws config
type AWS struct {
// AWS profile to use

View File

@@ -51,6 +51,7 @@ func (c TOMLLoader) Load(pathToToml, keyPass string) error {
Conf.CveDict = conf.CveDict
Conf.OvalDict = conf.OvalDict
Conf.Gost = conf.Gost
Conf.Exploit = conf.Exploit
d := conf.Default
Conf.Default = d
@@ -104,7 +105,6 @@ func (c TOMLLoader) Load(pathToToml, keyPass string) error {
}
}
// s.KeyPassword = keyPass
s.KeyPassword = v.KeyPassword
if len(s.KeyPassword) == 0 {
s.KeyPassword = d.KeyPassword

135
exploit/exploit.go Normal file
View File

@@ -0,0 +1,135 @@
/* 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, paperURL, 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
}
if os.Paper != nil {
paperURL = &os.Paper.PaperURL
}
}
exploit := models.Exploit{
ExploitType: e.ExploitType,
ID: e.ExploitUniqueID,
URL: e.URL,
Description: e.Description,
DocumentURL: documentURL,
ShellCodeURL: shellURL,
PaperURL: paperURL,
}
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
}

8
exploit/exploit_test.go Normal file
View File

@@ -0,0 +1,8 @@
package exploit
import (
"testing"
)
func TestSetPackageStates(t *testing.T) {
}

133
exploit/util.go Normal file
View File

@@ -0,0 +1,133 @@
/* 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,
}
}

View File

@@ -55,7 +55,7 @@ func (deb Debian) FillWithGost(driver db.DB, r *models.ScanResult) (nCVEs int, e
}
packCvesList := []packCves{}
if deb.isFetchViaHTTP() {
if config.Conf.Gost.IsFetchViaHTTP() {
url, _ := util.URLPathJoin(config.Conf.Gost.URL, "debian", major(r.Release), "pkgs")
responses, err := getAllUnfixedCvesViaHTTP(r, url)
if err != nil {
@@ -115,7 +115,11 @@ func (deb Debian) FillWithGost(driver db.DB, r *models.ScanResult) (nCVEs int, e
for _, cve := range p.cves {
v, ok := r.ScannedCves[cve.CveID]
if ok {
v.CveContents[models.DebianSecurityTracker] = cve
if v.CveContents == nil {
v.CveContents = models.NewCveContents(cve)
} else {
v.CveContents[models.DebianSecurityTracker] = cve
}
} else {
v = models.VulnInfo{
CveID: cve.CveID,

View File

@@ -46,6 +46,8 @@ func NewClient(family string) Client {
return RedHat{}
case cnf.Debian:
return Debian{}
case cnf.Windows:
return Microsoft{}
default:
return Pseudo{}
}
@@ -58,7 +60,7 @@ type Base struct {
// CheckHTTPHealth do health check
func (b Base) CheckHTTPHealth() error {
if !b.isFetchViaHTTP() {
if !cnf.Conf.Gost.IsFetchViaHTTP() {
return nil
}
@@ -87,11 +89,6 @@ func (b Base) CheckIfGostFresh(driver db.DB, osFamily string) (ok bool, err erro
return true, nil
}
func (b Base) isFetchViaHTTP() bool {
// Default value of OvalDBType is sqlite3
return cnf.Conf.Gost.URL != "" && cnf.Conf.Gost.Type == "sqlite3"
}
// Pseudo is Gost client except for RedHat family and Debian
type Pseudo struct {
Base

116
gost/microsoft.go Normal file
View File

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

View File

@@ -51,7 +51,7 @@ func (red RedHat) fillFixed(driver db.DB, r *models.ScanResult) error {
cveIDs = append(cveIDs, cveID)
}
if red.isFetchViaHTTP() {
if config.Conf.Gost.IsFetchViaHTTP() {
prefix, _ := util.URLPathJoin(config.Conf.Gost.URL,
"redhat", "cves")
responses, err := getCvesViaHTTP(cveIDs, prefix)
@@ -67,8 +67,20 @@ func (red RedHat) fillFixed(driver db.DB, r *models.ScanResult) error {
continue
}
cveCont := red.ConvertToModel(&redCve)
v, _ := r.ScannedCves[res.request.cveID]
v.CveContents[models.RedHatAPI] = *cveCont
v, ok := r.ScannedCves[res.request.cveID]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{
CveID: cveCont.CveID,
CveContents: models.NewCveContents(*cveCont),
Confidences: models.Confidences{models.RedHatAPIMatch},
}
}
r.ScannedCves[res.request.cveID] = v
}
} else {
@@ -80,8 +92,20 @@ func (red RedHat) fillFixed(driver db.DB, r *models.ScanResult) error {
continue
}
cveCont := red.ConvertToModel(&redCve)
v, _ := r.ScannedCves[cveID]
v.CveContents[models.RedHatAPI] = *cveCont
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
}
}
@@ -90,7 +114,7 @@ func (red RedHat) fillFixed(driver db.DB, r *models.ScanResult) error {
}
func (red RedHat) fillUnfixed(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
if red.isFetchViaHTTP() {
if config.Conf.Gost.IsFetchViaHTTP() {
prefix, _ := util.URLPathJoin(config.Conf.Gost.URL,
"redhat", major(r.Release), "pkgs")
responses, err := getAllUnfixedCvesViaHTTP(r, prefix)
@@ -108,7 +132,11 @@ func (red RedHat) fillUnfixed(driver db.DB, r *models.ScanResult) (nCVEs int, er
cveCont := red.ConvertToModel(&cve)
v, ok := r.ScannedCves[cve.Name]
if ok {
v.CveContents[models.RedHatAPI] = *cveCont
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{
CveID: cveCont.CveID,
@@ -117,7 +145,6 @@ func (red RedHat) fillUnfixed(driver db.DB, r *models.ScanResult) (nCVEs int, er
}
nCVEs++
}
pkgStats := red.mergePackageStates(v,
cve.PackageState, r.Packages, r.Release)
if 0 < len(pkgStats) {
@@ -138,7 +165,11 @@ func (red RedHat) fillUnfixed(driver db.DB, r *models.ScanResult) (nCVEs int, er
cveCont := red.ConvertToModel(&cve)
v, ok := r.ScannedCves[cve.Name]
if ok {
v.CveContents[models.RedHatAPI] = *cveCont
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{
CveID: cveCont.CveID,
@@ -192,18 +223,23 @@ func (red RedHat) mergePackageStates(v models.VulnInfo, ps []gostmodels.RedhatPa
return
}
// ConvertToModel converts gost model to vuls model
func (red RedHat) ConvertToModel(cve *gostmodels.RedhatCVE) *models.CveContent {
cwes := []string{}
if cve.Cwe != "" {
s := strings.TrimPrefix(cve.Cwe, "(")
s = strings.TrimSuffix(s, ")")
if strings.Contains(cve.Cwe, "|") {
cwes = strings.Split(cve.Cwe, "|")
} else {
cwes = strings.Split(s, "->")
func (red RedHat) parseCwe(str string) (cwes []string) {
if str != "" {
s := strings.Replace(str, "(", "|", -1)
s = strings.Replace(s, ")", "|", -1)
s = strings.Replace(s, "->", "|", -1)
for _, s := range strings.Split(s, "|") {
if s != "" {
cwes = append(cwes, s)
}
}
}
return
}
// ConvertToModel converts gost model to vuls model
func (red RedHat) ConvertToModel(cve *gostmodels.RedhatCVE) *models.CveContent {
cwes := red.parseCwe(cve.Cwe)
details := []string{}
for _, detail := range cve.Details {

37
gost/redhat_test.go Normal file
View File

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

View File

@@ -228,6 +228,8 @@ func NewCveContentType(name string) CveContentType {
return RedHatAPI
case "debian_security_tracker":
return DebianSecurityTracker
case "microsoft":
return Microsoft
default:
return Unknown
}
@@ -264,6 +266,9 @@ const (
// SUSE is SUSE Linux
SUSE CveContentType = "suse"
// Microsoft is Microsoft
Microsoft CveContentType = "microsoft"
// Unknown is Unknown
Unknown CveContentType = "unknown"
)

View File

@@ -45,6 +45,7 @@ type ScanResult struct {
IPv4Addrs []string `json:"ipv4Addrs,omitempty"` // only global unicast address (https://golang.org/pkg/net/#IP.IsGlobalUnicast)
IPv6Addrs []string `json:"ipv6Addrs,omitempty"` // only global unicast address (https://golang.org/pkg/net/#IP.IsGlobalUnicast)
ScannedAt time.Time `json:"scannedAt"`
ScanMode string `json:"scanMode"`
ScannedVersion string `json:"scannedVersion"`
ScannedRevision string `json:"scannedRevision"`
ScannedBy string `json:"scannedBy"`
@@ -309,12 +310,13 @@ func (r ScanResult) FormatTextReportHeadedr() string {
buf.WriteString("=")
}
return fmt.Sprintf("%s\n%s\n%s, %s, %s\n",
return fmt.Sprintf("%s\n%s\n%s, %s, %s, %s\n",
r.ServerInfo(),
buf.String(),
r.ScannedCves.FormatCveSummary(),
r.ScannedCves.FormatFixedStatus(r.Packages),
r.FormatUpdatablePacksSummary(),
r.FormatExploitCveSummary(),
)
}
@@ -338,6 +340,17 @@ func (r ScanResult) FormatUpdatablePacksSummary() string {
nUpdatable)
}
// FormatExploitCveSummary returns a summary of exploit cve
func (r ScanResult) FormatExploitCveSummary() string {
nExploitCve := 0
for _, vuln := range r.ScannedCves {
if 0 < len(vuln.Exploits) {
nExploitCve++
}
}
return fmt.Sprintf("%d exploits", nExploitCve)
}
func (r ScanResult) isDisplayUpdatableNum() bool {
var mode config.ScanMode
s, _ := config.Conf.Servers[r.ServerName]

View File

@@ -25,6 +25,7 @@ import (
"time"
"github.com/future-architect/vuls/config"
exploitmodels "github.com/mozqnet/go-exploitdb/models"
)
// VulnInfos has a map of VulnInfo
@@ -166,6 +167,7 @@ type VulnInfo struct {
DistroAdvisories []DistroAdvisory `json:"distroAdvisories,omitempty"` // for Aamazon, RHEL, FreeBSD
CpeURIs []string `json:"cpeURIs,omitempty"` // CpeURIs related to this CVE defined in config.toml
CveContents CveContents `json:"cveContents"`
Exploits []Exploit `json:"exploits"`
}
// Titles returns tilte (TUI)
@@ -713,6 +715,18 @@ func (p DistroAdvisory) Format() string {
return strings.Join(buf, "\n")
}
// Exploit :
type Exploit struct {
ExploitType exploitmodels.ExploitType `json:"exploitType"`
ID string `json:"id"`
URL string `json:"url"`
Description string `json:"description"`
DocumentURL *string `json:"documentURL,omitempty"`
PaperURL *string `json:"paperURL,omitempty"`
ShellCodeURL *string `json:"shellCodeURL,omitempty"`
BinaryURL *string `json:"binaryURL,omitempty"`
}
// Confidences is a list of Confidence
type Confidences []Confidence

View File

@@ -41,7 +41,7 @@ func NewAlpine() Alpine {
// FillWithOval returns scan result after updating CVE info by OVAL
func (o Alpine) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
var relatedDefs ovalResult
if o.IsFetchViaHTTP() {
if config.Conf.OvalDict.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
return 0, err
}

View File

@@ -133,7 +133,7 @@ func (o Debian) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err
}
var relatedDefs ovalResult
if o.IsFetchViaHTTP() {
if config.Conf.OvalDict.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
return 0, err
}
@@ -243,7 +243,7 @@ func (o Ubuntu) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err
}
var relatedDefs ovalResult
if o.IsFetchViaHTTP() {
if config.Conf.OvalDict.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
return 0, err
}

View File

@@ -38,7 +38,6 @@ type Client interface {
// CheckIfOvalFetched checks if oval entries are in DB by family, release.
CheckIfOvalFetched(db.DB, string, string) (bool, error)
CheckIfOvalFresh(db.DB, string, string) (bool, error)
IsFetchViaHTTP() bool
}
// Base is a base struct
@@ -48,7 +47,7 @@ type Base struct {
// CheckHTTPHealth do health check
func (b Base) CheckHTTPHealth() error {
if !b.IsFetchViaHTTP() {
if !cnf.Conf.OvalDict.IsFetchViaHTTP() {
return nil
}
@@ -67,7 +66,7 @@ func (b Base) CheckHTTPHealth() error {
// CheckIfOvalFetched checks if oval entries are in DB by family, release.
func (b Base) CheckIfOvalFetched(driver db.DB, osFamily, release string) (fetched bool, err error) {
if !b.IsFetchViaHTTP() {
if !cnf.Conf.OvalDict.IsFetchViaHTTP() {
count, err := driver.CountDefs(osFamily, release)
if err != nil {
return false, fmt.Errorf("Failed to count OVAL defs: %s, %s, %v",
@@ -93,7 +92,7 @@ func (b Base) CheckIfOvalFetched(driver db.DB, osFamily, release string) (fetche
// CheckIfOvalFresh checks if oval entries are fresh enough
func (b Base) CheckIfOvalFresh(driver db.DB, osFamily, release string) (ok bool, err error) {
var lastModified time.Time
if !b.IsFetchViaHTTP() {
if !cnf.Conf.OvalDict.IsFetchViaHTTP() {
lastModified = driver.GetLastModified(osFamily, release)
} else {
url, _ := util.URLPathJoin(cnf.Conf.OvalDict.URL, "lastmodified", osFamily, release)
@@ -119,9 +118,3 @@ func (b Base) CheckIfOvalFresh(driver db.DB, osFamily, release string) (ok bool,
util.Log.Infof("OVAL is fresh: %s %s ", osFamily, release)
return true, nil
}
// IsFetchViaHTTP checks whether fetch via HTTP
func (b Base) IsFetchViaHTTP() bool {
// Default value of OvalDBType is sqlite3
return cnf.Conf.OvalDict.URL != "" && cnf.Conf.OvalDict.Type == "sqlite3"
}

View File

@@ -37,7 +37,7 @@ type RedHatBase struct {
// FillWithOval returns scan result after updating CVE info by OVAL
func (o RedHatBase) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
var relatedDefs ovalResult
if o.IsFetchViaHTTP() {
if config.Conf.OvalDict.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
return 0, err
}

View File

@@ -43,7 +43,7 @@ func NewSUSE() SUSE {
// FillWithOval returns scan result after updating CVE info by OVAL
func (o SUSE) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
var relatedDefs ovalResult
if o.IsFetchViaHTTP() {
if config.Conf.OvalDict.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
return 0, err
}

View File

@@ -136,7 +136,7 @@ func createBlockBlob(cli storage.BlobStorageClient, k string, b []byte) error {
if b, err = gz(b); err != nil {
return err
}
k = k + ".gz"
k += ".gz"
}
ref := cli.GetContainerReference(c.Conf.Azure.ContainerName)

View File

@@ -45,7 +45,7 @@ func (api *cvedictClient) initialize() {
}
func (api cvedictClient) CheckHealth() error {
if !api.isFetchViaHTTP() {
if !config.Conf.CveDict.IsFetchViaHTTP() {
util.Log.Debugf("get cve-dictionary from %s", config.Conf.CveDict.Type)
return nil
}
@@ -69,7 +69,7 @@ type response struct {
}
func (api cvedictClient) FetchCveDetails(driver cvedb.DB, cveIDs []string) (cveDetails []cve.CveDetail, err error) {
if !api.isFetchViaHTTP() {
if !config.Conf.CveDict.IsFetchViaHTTP() {
for _, cveID := range cveIDs {
cveDetail, err := driver.Get(cveID)
if err != nil {
@@ -176,16 +176,8 @@ func (api cvedictClient) httpGet(key, url string, resChan chan<- response, errCh
}
}
func (api cvedictClient) isFetchViaHTTP() bool {
// Default value of CveDBType is sqlite3
if config.Conf.CveDict.URL != "" && config.Conf.CveDict.Type == "sqlite3" {
return true
}
return false
}
func (api cvedictClient) FetchCveDetailsByCpeName(driver cvedb.DB, cpeName string) ([]cve.CveDetail, error) {
if api.isFetchViaHTTP() {
if config.Conf.CveDict.IsFetchViaHTTP() {
api.baseURL = config.Conf.CveDict.URL
url, err := util.URLPathJoin(api.baseURL, "cpes")
if err != nil {

View File

@@ -9,13 +9,15 @@ import (
gostdb "github.com/knqyf263/gost/db"
cvedb "github.com/kotakanbe/go-cve-dictionary/db"
ovaldb "github.com/kotakanbe/goval-dictionary/db"
exploitdb "github.com/mozqnet/go-exploitdb/db"
)
// DBClient is a dictionarie's db client for reporting
type DBClient struct {
CveDB cvedb.DB
OvalDB ovaldb.DB
GostDB gostdb.DB
CveDB cvedb.DB
OvalDB ovaldb.DB
GostDB gostdb.DB
ExploitDB exploitdb.DB
}
// DBClientConf has a configuration of Vulnerability DBs
@@ -23,25 +25,17 @@ type DBClientConf struct {
CveDictCnf config.GoCveDictConf
OvalDictCnf config.GovalDictConf
GostCnf config.GostConf
ExploitCnf config.ExploitConf
DebugSQL bool
}
func (c DBClientConf) isCveDBViaHTTP() bool {
return c.CveDictCnf.URL != "" && c.CveDictCnf.Type == "sqlite3"
}
func (c DBClientConf) isOvalViaHTTP() bool {
return c.OvalDictCnf.URL != "" && c.OvalDictCnf.Type == "sqlite3"
}
func (c DBClientConf) isGostViaHTTP() bool {
return c.GostCnf.URL != "" && c.GostCnf.Type == "sqlite3"
}
// NewDBClient returns db clients
func NewDBClient(cnf DBClientConf) (dbclient *DBClient, locked bool, err error) {
cveDriver, locked, err := NewCveDB(cnf)
if err != nil {
if locked {
return nil, true, fmt.Errorf("CveDB is locked: %s",
cnf.OvalDictCnf.SQLite3Path)
} else if err != nil {
return nil, locked, err
}
@@ -63,16 +57,26 @@ func NewDBClient(cnf DBClientConf) (dbclient *DBClient, locked bool, err error)
cnf.GostCnf.SQLite3Path, err)
}
exploitdb, locked, err := NewExploitDB(cnf)
if locked {
return nil, true, fmt.Errorf("exploitDB is locked: %s",
cnf.ExploitCnf.SQLite3Path)
} else if err != nil {
util.Log.Warnf("Unable to use exploitDB: %s, err: %s",
cnf.ExploitCnf.SQLite3Path, err)
}
return &DBClient{
CveDB: cveDriver,
OvalDB: ovaldb,
GostDB: gostdb,
CveDB: cveDriver,
OvalDB: ovaldb,
GostDB: gostdb,
ExploitDB: exploitdb,
}, false, nil
}
// NewCveDB returns cve db client
func NewCveDB(cnf DBClientConf) (driver cvedb.DB, locked bool, err error) {
if cnf.isCveDBViaHTTP() {
if config.Conf.CveDict.IsFetchViaHTTP() {
return nil, false, nil
}
util.Log.Debugf("open cve-dictionary db (%s)", cnf.CveDictCnf.Type)
@@ -92,7 +96,7 @@ func NewCveDB(cnf DBClientConf) (driver cvedb.DB, locked bool, err error) {
// NewOvalDB returns oval db client
func NewOvalDB(cnf DBClientConf) (driver ovaldb.DB, locked bool, err error) {
if cnf.isOvalViaHTTP() {
if config.Conf.OvalDict.IsFetchViaHTTP() {
return nil, false, nil
}
path := cnf.OvalDictCnf.URL
@@ -119,7 +123,7 @@ func NewOvalDB(cnf DBClientConf) (driver ovaldb.DB, locked bool, err error) {
// NewGostDB returns db client for Gost
func NewGostDB(cnf DBClientConf) (driver gostdb.DB, locked bool, err error) {
if cnf.isGostViaHTTP() {
if config.Conf.Gost.IsFetchViaHTTP() {
return nil, false, nil
}
path := cnf.GostCnf.URL
@@ -143,6 +147,32 @@ func NewGostDB(cnf DBClientConf) (driver gostdb.DB, locked bool, err error) {
return driver, false, nil
}
// NewExploitDB returns db client for Exploit
func NewExploitDB(cnf DBClientConf) (driver exploitdb.DB, locked bool, err error) {
if config.Conf.Exploit.IsFetchViaHTTP() {
return nil, false, nil
}
path := cnf.ExploitCnf.URL
if cnf.ExploitCnf.Type == "sqlite3" {
path = cnf.ExploitCnf.SQLite3Path
if _, err := os.Stat(path); os.IsNotExist(err) {
util.Log.Warnf("--exploitdb-path=%s is not found. It's recommended to use exploit to improve scanning accuracy. To use exploit db database, see https://github.com/mozqnet/go-exploitdb", path)
return nil, false, nil
}
}
util.Log.Debugf("Open exploit db (%s): %s", cnf.ExploitCnf.Type, path)
if driver, locked, err = exploitdb.NewDB(cnf.ExploitCnf.Type, path, cnf.DebugSQL); err != nil {
if locked {
util.Log.Errorf("exploitDB is locked: %s", err)
return nil, true, err
}
return nil, false, err
}
return driver, false, nil
}
// CloseDB close dbs
func (d DBClient) CloseDB() {
if d.CveDB != nil {

View File

@@ -129,7 +129,7 @@ func writeFile(path string, data []byte, perm os.FileMode) error {
if data, err = gz(data); err != nil {
return err
}
path = path + ".gz"
path += ".gz"
}
return ioutil.WriteFile(path, []byte(data), perm)
}

View File

@@ -32,6 +32,7 @@ import (
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/contrib/owasp-dependency-check/parser"
"github.com/future-architect/vuls/cwe"
"github.com/future-architect/vuls/exploit"
"github.com/future-architect/vuls/gost"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/oval"
@@ -40,6 +41,7 @@ import (
gostdb "github.com/knqyf263/gost/db"
cvedb "github.com/kotakanbe/go-cve-dictionary/db"
ovaldb "github.com/kotakanbe/goval-dictionary/db"
exploitdb "github.com/mozqnet/go-exploitdb/db"
)
const (
@@ -54,6 +56,7 @@ func FillCveInfos(dbclient DBClient, rs []models.ScanResult, dir string) ([]mode
hostname, _ := os.Hostname()
for _, r := range rs {
if c.Conf.RefreshCve || needToRefreshCve(r) {
r.ScannedCves = models.VulnInfos{}
cpeURIs := []string{}
if len(r.Container.ContainerID) == 0 {
cpeURIs = c.Conf.Servers[r.ServerName].CpeNames
@@ -176,6 +179,14 @@ func FillCveInfo(dbclient DBClient, r *models.ScanResult, cpeURIs []string) erro
return fmt.Errorf("Failed to fill with CVE: %s", err)
}
util.Log.Infof("Fill exploit information with Exploit-DB")
nExploitCve, err := FillWithExploit(dbclient.ExploitDB, r)
if err != nil {
return fmt.Errorf("Failed to fill with exploit: %s", err)
}
util.Log.Infof("%s: %d exploits are detected",
r.FormatServerName(), nExploitCve)
fillCweDict(r)
return nil
}
@@ -256,16 +267,16 @@ func FillWithOval(driver ovaldb.DB, r *models.ScanResult) (nCVEs int, err error)
return 0, fmt.Errorf("OVAL for %s is not implemented yet", r.Family)
}
if !ovalClient.IsFetchViaHTTP() && driver == nil {
return 0, nil
if !c.Conf.OvalDict.IsFetchViaHTTP() {
if driver == nil {
return 0, nil
}
if err = driver.NewOvalDB(ovalFamily); err != nil {
return 0, fmt.Errorf("Failed to New Oval DB. err: %s", err)
}
}
if err = driver.NewOvalDB(ovalFamily); err != nil {
return 0, fmt.Errorf("Failed to New Oval DB. err: %s", err)
}
util.Log.Debugf("Check whether oval fetched: %s %s",
ovalFamily, r.Release)
util.Log.Debugf("Check whether oval fetched: %s %s", ovalFamily, r.Release)
ok, err := ovalClient.CheckIfOvalFetched(driver, ovalFamily, r.Release)
if err != nil {
return 0, err
@@ -292,6 +303,14 @@ func FillWithGost(driver gostdb.DB, r *models.ScanResult) (nCVEs int, err error)
return gostClient.FillWithGost(driver, r)
}
// FillWithExploit fills Exploits with exploit dataabase
// https://github.com/mozqnet/go-exploitdb
func FillWithExploit(driver exploitdb.DB, r *models.ScanResult) (nExploitCve int, err error) {
// TODO chekc if fetched
// TODO chekc if fresh enough
return exploit.FillWithExploit(driver, r)
}
func fillVulnByCpeURIs(driver cvedb.DB, r *models.ScanResult, cpeURIs []string) (nCVEs int, err error) {
for _, name := range cpeURIs {
details, err := CveClient.FetchCveDetailsByCpeName(driver, name)
@@ -454,6 +473,7 @@ func EnsureUUIDs(configPath string, results models.ScanResults) error {
cveDict := &c.Conf.CveDict
ovalDict := &c.Conf.OvalDict
gost := &c.Conf.Gost
exploit := &c.Conf.Exploit
http := &c.Conf.HTTP
if http.URL == "" {
http = nil
@@ -498,6 +518,7 @@ func EnsureUUIDs(configPath string, results models.ScanResults) error {
CveDict *c.GoCveDictConf `toml:"cveDict"`
OvalDict *c.GovalDictConf `toml:"ovalDict"`
Gost *c.GostConf `toml:"gost"`
Exploit *c.ExploitConf `toml:"exploit"`
Slack *c.SlackConf `toml:"slack"`
Email *c.SMTPConf `toml:"email"`
HTTP *c.HTTPConf `toml:"http"`
@@ -515,6 +536,7 @@ func EnsureUUIDs(configPath string, results models.ScanResults) error {
CveDict: cveDict,
OvalDict: ovalDict,
Gost: gost,
Exploit: exploit,
Slack: slack,
Email: email,
HTTP: http,

View File

@@ -144,7 +144,7 @@ func putObject(svc *s3.S3, k string, b []byte) error {
if b, err = gz(b); err != nil {
return err
}
k = k + ".gz"
k += ".gz"
}
putObjectInput := &s3.PutObjectInput{

View File

@@ -19,9 +19,10 @@ package report
import (
"fmt"
"log/syslog"
"strings"
syslog "github.com/RackSec/srslog"
"github.com/pkg/errors"
"github.com/future-architect/vuls/config"

View File

@@ -51,16 +51,14 @@ func RunTui(results models.ScanResults) subcommands.ExitStatus {
return scanResults[i].ServerName < scanResults[j].ServerName
})
// g, err := gocui.NewGui(gocui.OutputNormal)
g := gocui.NewGui()
if err := g.Init(); err != nil {
g, err := gocui.NewGui(gocui.OutputNormal)
if err != nil {
util.Log.Errorf("%s", err)
return subcommands.ExitFailure
}
defer g.Close()
g.SetLayout(layout)
// g.SetManagerFunc(layout)
g.SetManagerFunc(layout)
if err := keybindings(g); err != nil {
util.Log.Errorf("%s", err)
return subcommands.ExitFailure
@@ -185,19 +183,19 @@ func nextView(g *gocui.Gui, v *gocui.View) error {
var err error
if v == nil {
err = g.SetCurrentView("side")
_, err = g.SetCurrentView("side")
}
switch v.Name() {
case "side":
err = g.SetCurrentView("summary")
_, err = g.SetCurrentView("summary")
case "summary":
err = g.SetCurrentView("detail")
_, err = g.SetCurrentView("detail")
case "detail":
err = g.SetCurrentView("changelog")
_, err = g.SetCurrentView("changelog")
case "changelog":
err = g.SetCurrentView("side")
_, err = g.SetCurrentView("side")
default:
err = g.SetCurrentView("summary")
_, err = g.SetCurrentView("summary")
}
return err
}
@@ -206,19 +204,19 @@ func previousView(g *gocui.Gui, v *gocui.View) error {
var err error
if v == nil {
err = g.SetCurrentView("side")
_, err = g.SetCurrentView("side")
}
switch v.Name() {
case "side":
err = g.SetCurrentView("side")
_, err = g.SetCurrentView("side")
case "summary":
err = g.SetCurrentView("side")
_, err = g.SetCurrentView("side")
case "detail":
err = g.SetCurrentView("summary")
_, err = g.SetCurrentView("summary")
case "changelog":
err = g.SetCurrentView("detail")
_, err = g.SetCurrentView("detail")
default:
err = g.SetCurrentView("side")
_, err = g.SetCurrentView("side")
}
return err
}
@@ -401,7 +399,7 @@ func cursorPageUp(g *gocui.Gui, v *gocui.View) error {
func previousSummary(g *gocui.Gui, v *gocui.View) error {
if v != nil {
// cursor to summary
if err := g.SetCurrentView("summary"); err != nil {
if _, err := g.SetCurrentView("summary"); err != nil {
return err
}
// move next line
@@ -409,7 +407,7 @@ func previousSummary(g *gocui.Gui, v *gocui.View) error {
return err
}
// cursor to detail
if err := g.SetCurrentView("detail"); err != nil {
if _, err := g.SetCurrentView("detail"); err != nil {
return err
}
}
@@ -419,7 +417,7 @@ func previousSummary(g *gocui.Gui, v *gocui.View) error {
func nextSummary(g *gocui.Gui, v *gocui.View) error {
if v != nil {
// cursor to summary
if err := g.SetCurrentView("summary"); err != nil {
if _, err := g.SetCurrentView("summary"); err != nil {
return err
}
// move next line
@@ -427,7 +425,7 @@ func nextSummary(g *gocui.Gui, v *gocui.View) error {
return err
}
// cursor to detail
if err := g.SetCurrentView("detail"); err != nil {
if _, err := g.SetCurrentView("detail"); err != nil {
return err
}
}
@@ -501,7 +499,7 @@ func getLine(g *gocui.Gui, v *gocui.View) error {
return err
}
fmt.Fprintln(v, l)
if err := g.SetCurrentView("msg"); err != nil {
if _, err := g.SetCurrentView("msg"); err != nil {
return err
}
}
@@ -524,7 +522,7 @@ func showMsg(g *gocui.Gui, v *gocui.View) error {
return err
}
fmt.Fprintln(v, l)
if err := g.SetCurrentView("msg"); err != nil {
if _, err := g.SetCurrentView("msg"); err != nil {
return err
}
}
@@ -535,7 +533,8 @@ func delMsg(g *gocui.Gui, v *gocui.View) error {
if err := g.DeleteView("msg"); err != nil {
return err
}
return g.SetCurrentView("summary")
_, err := g.SetCurrentView("summary")
return err
}
func quit(g *gocui.Gui, v *gocui.View) error {
@@ -584,7 +583,7 @@ func setSideLayout(g *gocui.Gui) error {
}
currentScanResult = scanResults[0]
vinfos = scanResults[0].ScannedCves.ToSortedSlice()
if err := g.SetCurrentView("side"); err != nil {
if _, err := g.SetCurrentView("side"); err != nil {
return err
}
}
@@ -710,9 +709,17 @@ func setChangelogLayout(g *gocui.Gui) error {
for _, affected := range vinfo.AffectedPackages {
// packages detected by OVAL may not be actually installed
if pack, ok := currentScanResult.Packages[affected.Name]; ok {
lines = append(lines,
"* "+pack.FormatVersionFromTo(
affected.NotFixedYet, affected.FixState))
var line string
if pack.Repository != "" {
line = fmt.Sprintf("* %s (%s)",
pack.FormatVersionFromTo(affected.NotFixedYet, affected.FixState),
pack.Repository)
} else {
line = fmt.Sprintf("* %s",
pack.FormatVersionFromTo(affected.NotFixedYet, affected.FixState),
)
}
lines = append(lines, line)
if len(pack.AffectedProcs) != 0 {
for _, p := range pack.AffectedProcs {
@@ -736,6 +743,16 @@ func setChangelogLayout(g *gocui.Gui) error {
lines = append(lines, adv.Format())
}
if len(vinfo.Exploits) != 0 {
lines = append(lines, "\n",
"Exploit Codes",
"=============",
)
for _, exploit := range vinfo.Exploits {
lines = append(lines, fmt.Sprintf("* [%s](%s)", exploit.Description, exploit.URL))
}
}
if currentScanResult.IsDeepScanMode() {
lines = append(lines, "\n",
"ChangeLogs",
@@ -763,6 +780,7 @@ func setChangelogLayout(g *gocui.Gui) error {
type dataForTmpl struct {
CveID string
Cvsses string
Exploits []models.Exploit
Summary string
Mitigation string
Confidences models.Confidences
@@ -870,6 +888,7 @@ const mdTemplate = `
CVSS Scores
-----------
{{.Cvsses }}
Summary
-----------
{{.Summary }}

View File

@@ -50,6 +50,7 @@ func formatScanSummary(rs ...models.ScanResult) string {
r.FormatServerName(),
fmt.Sprintf("%s%s", r.Family, r.Release),
r.FormatUpdatablePacksSummary(),
r.FormatExploitCveSummary(),
}
} else {
cols = []interface{}{
@@ -76,6 +77,7 @@ func formatOneLineSummary(rs ...models.ScanResult) string {
r.ScannedCves.FormatCveSummary(),
r.ScannedCves.FormatFixedStatus(r.Packages),
r.FormatUpdatablePacksSummary(),
r.FormatExploitCveSummary(),
}
} else {
cols = []interface{}{
@@ -123,6 +125,7 @@ No CVE-IDs are found in updatable packages.
fmt.Sprintf("%7s", vinfo.PatchStatus(r.Packages)),
// packname,
fmt.Sprintf("https://nvd.nist.gov/vuln/detail/%s", vinfo.CveID),
fmt.Sprintf("%t", 0 < len(vinfo.Exploits)),
})
}
@@ -137,6 +140,7 @@ No CVE-IDs are found in updatable packages.
"Fixed",
// "Pkg",
"NVD",
"Exploit",
})
table.SetBorder(true)
table.AppendBulk(data)
@@ -203,8 +207,18 @@ No CVE-IDs are found in updatable packages.
vuln.AffectedPackages.Sort()
for _, affected := range vuln.AffectedPackages {
if pack, ok := r.Packages[affected.Name]; ok {
data = append(data, []string{"Affected PKG",
pack.FormatVersionFromTo(affected.NotFixedYet, affected.FixState)})
var line string
if pack.Repository != "" {
line = fmt.Sprintf("%s (%s)",
pack.FormatVersionFromTo(affected.NotFixedYet, affected.FixState),
pack.Repository)
} else {
line = fmt.Sprintf("%s",
pack.FormatVersionFromTo(affected.NotFixedYet, affected.FixState),
)
}
data = append(data, []string{"Affected Pkg", line})
if len(pack.AffectedProcs) != 0 {
for _, p := range pack.AffectedProcs {
data = append(data, []string{"",
@@ -240,6 +254,9 @@ No CVE-IDs are found in updatable packages.
for _, url := range cweURLs {
data = append(data, []string{"CWE", url})
}
for _, exploit := range vuln.Exploits {
data = append(data, []string{string(exploit.ExploitType), exploit.URL})
}
for _, url := range top10URLs {
data = append(data, []string{"OWASP Top10", url})
}
@@ -259,10 +276,6 @@ No CVE-IDs are found in updatable packages.
"",
})
table.SetBorder(true)
table.SetHeaderColor(
tablewriter.Colors{tablewriter.Normal},
tablewriter.Colors{tablewriter.Normal},
)
table.AppendBulk(data)
table.Render()
lines += b.String() + "\n"

View File

@@ -391,6 +391,7 @@ func (l *base) convertToModel() models.ScanResult {
JSONVersion: models.JSONVersion,
ServerName: l.ServerInfo.ServerName,
ScannedAt: time.Now(),
ScanMode: l.ServerInfo.Mode.String(),
Family: l.Distro.Family,
Release: l.Distro.Release,
Container: container,

View File

@@ -62,7 +62,7 @@ func detectDebian(c config.ServerInfo) (itsMe bool, deb osTypeInterface, err err
return false, deb, nil
}
if r.ExitStatus == 255 {
return false, deb, fmt.Errorf("Unable to connect via SSH. Check SSH settings. If you have never SSH to the host to be scanned, SSH to the host before scanning in order to add the HostKey. %s@%s port: %s\n%s", c.User, c.Host, c.Port, r)
return false, deb, fmt.Errorf("Unable to connect via SSH. Scan with -vvv option to print SSH debugging messages and check SSH settings. If you have never SSH to the host to be scanned, SSH to the host before scanning in order to add the HostKey. %s@%s port: %s\n%s", c.User, c.Host, c.Port, r)
}
util.Log.Debugf("Not Debian like Linux. %s", r)
return false, deb, nil