Add: source code

This commit is contained in:
kota kanbe
2016-04-01 14:36:50 +09:00
parent 9ee9641a8a
commit f4fb0b5463
39 changed files with 7546 additions and 0 deletions

158
commands/discover.go Normal file
View File

@@ -0,0 +1,158 @@
/* Vuls - Vulnerability Scanner
Copyright (C) 2016 Future Architect, Inc. Japan.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package commands
import (
"flag"
"fmt"
"os"
"strings"
"text/template"
"github.com/google/subcommands"
"golang.org/x/net/context"
"github.com/Sirupsen/logrus"
ps "github.com/kotakanbe/go-pingscanner"
)
// DiscoverCmd is Subcommand of host discovery mode
type DiscoverCmd struct {
}
// Name return subcommand name
func (*DiscoverCmd) Name() string { return "discover" }
// Synopsis return synopsis
func (*DiscoverCmd) Synopsis() string { return "Host discovery in the CIDR." }
// Usage return usage
func (*DiscoverCmd) Usage() string {
return `discover:
discover 192.168.0.0/24
`
}
// SetFlags set flag
func (p *DiscoverCmd) SetFlags(f *flag.FlagSet) {
}
// Execute execute
func (p *DiscoverCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
// validate
if len(f.Args()) == 0 {
return subcommands.ExitUsageError
}
for _, cidr := range f.Args() {
scanner := ps.PingScanner{
CIDR: cidr,
PingOptions: []string{
"-c1",
"-t1",
},
NumOfConcurrency: 100,
}
hosts, err := scanner.Scan()
if err != nil {
logrus.Errorf("Host Discovery failed. err: %s", err)
return subcommands.ExitFailure
}
if len(hosts) < 1 {
logrus.Errorf("Active hosts not found in %s.", cidr)
return subcommands.ExitSuccess
} else if err := printConfigToml(hosts); err != nil {
logrus.Errorf("Failed to parse template. err: %s", err)
return subcommands.ExitFailure
}
}
return subcommands.ExitSuccess
}
// Output the tmeplate of config.toml
func printConfigToml(ips []string) (err error) {
const tomlTempale = `
[slack]
hookURL = "https://hooks.slack.com/services/abc123/defghijklmnopqrstuvwxyz"
channel = "#channel-name"
#channel = "#{servername}"
iconEmoji = ":ghost:"
authUser = "username"
notifyUsers = ["@username"]
[mail]
smtpAddr = "smtp.gmail.com"
smtpPort = 465
user = "username"
password = "password"
from = "from@address.com"
to = ["to@address.com"]
cc = ["cc@address.com"]
subjectPrefix = "[vuls]"
[default]
#port = "22"
#user = "username"
#password = "password"
#keyPath = "/home/username/.ssh/id_rsa"
#keyPassword = "password"
[servers]
{{- $names:= .Names}}
{{range $i, $ip := .IPs}}
[servers.{{index $names $i}}]
host = "{{$ip}}"
#port = "22"
#user = "root"
#password = "password"
#keyPath = "/home/username/.ssh/id_rsa"
#keyPassword = "password"
#cpeNames = [
# "cpe:/a:rubyonrails:ruby_on_rails:4.2.1",
#]
{{end}}
`
var tpl *template.Template
if tpl, err = template.New("tempalte").Parse(tomlTempale); err != nil {
return
}
type activeHosts struct {
IPs []string
Names []string
}
a := activeHosts{IPs: ips}
names := []string{}
for _, ip := range ips {
// TOML section header must not contain "."
name := strings.Replace(ip, ".", "-", -1)
names = append(names, name)
}
a.Names = names
fmt.Println("# Create config.toml using below and then ./vuls --config=/path/to/config.toml")
if err = tpl.Execute(os.Stdout, a); err != nil {
return
}
return
}

131
commands/prepare.go Normal file
View File

@@ -0,0 +1,131 @@
/* Vuls - Vulnerability Scanner
Copyright (C) 2016 Future Architect, Inc. Japan.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package commands
import (
"flag"
"os"
"github.com/Sirupsen/logrus"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/scan"
"github.com/future-architect/vuls/util"
"github.com/google/subcommands"
"golang.org/x/net/context"
)
// PrepareCmd is Subcommand of host discovery mode
type PrepareCmd struct {
debug bool
configPath string
useUnattendedUpgrades bool
}
// Name return subcommand name
func (*PrepareCmd) Name() string { return "prepare" }
// Synopsis return synopsis
func (*PrepareCmd) Synopsis() string {
// return "Install packages Ubuntu: unattended-upgrade, CentOS: yum-plugin-security)"
return `Install required packages to scan.
CentOS: yum-plugin-security, yum-plugin-changelog
Amazon: None
RHEL: TODO
Ubuntu: None
`
}
// Usage return usage
func (*PrepareCmd) Usage() string {
return `prepare:
prepare [-config=/path/to/config.toml] [-debug]
`
}
// SetFlags set flag
func (p *PrepareCmd) SetFlags(f *flag.FlagSet) {
f.BoolVar(&p.debug, "debug", false, "debug mode")
defaultConfPath := os.Getenv("PWD") + "/config.toml"
f.StringVar(&p.configPath, "config", defaultConfPath, "/path/to/toml")
f.BoolVar(
&p.useUnattendedUpgrades,
"use-unattended-upgrades",
false,
"[Depricated] For Ubuntu, install unattended-upgrades",
)
}
// Execute execute
func (p *PrepareCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
logrus.Infof("Begin Preparing (config: %s)", p.configPath)
err := c.Load(p.configPath)
if err != nil {
logrus.Errorf("Error loading %s, %s", p.configPath, err)
return subcommands.ExitUsageError
}
target := make(map[string]c.ServerInfo)
for _, arg := range f.Args() {
found := false
for servername, info := range c.Conf.Servers {
if servername == arg {
target[servername] = info
found = true
break
}
}
if !found {
logrus.Errorf("%s is not in config", arg)
return subcommands.ExitUsageError
}
}
if 0 < len(f.Args()) {
c.Conf.Servers = target
}
c.Conf.Debug = p.debug
c.Conf.UseUnattendedUpgrades = p.useUnattendedUpgrades
// Set up custom logger
logger := util.NewCustomLogger(c.ServerInfo{})
logger.Info("Detecting OS... ")
err = scan.InitServers(logger)
if err != nil {
logger.Errorf("Failed to init servers. err: %s", err)
return subcommands.ExitFailure
}
logger.Info("Installing...")
if errs := scan.Prepare(); 0 < len(errs) {
for _, e := range errs {
logger.Errorf("Failed: %s.", e)
}
return subcommands.ExitFailure
}
logger.Info("Success")
return subcommands.ExitSuccess
}

241
commands/scan.go Normal file
View File

@@ -0,0 +1,241 @@
/* Vuls - Vulnerability Scanner
Copyright (C) 2016 Future Architect, Inc. Japan.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package commands
import (
"flag"
"os"
"github.com/Sirupsen/logrus"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/cveapi"
"github.com/future-architect/vuls/db"
"github.com/future-architect/vuls/report"
"github.com/future-architect/vuls/scan"
"github.com/future-architect/vuls/util"
"github.com/google/subcommands"
"golang.org/x/net/context"
)
// ScanCmd is Subcommand of host discovery mode
type ScanCmd struct {
lang string
debug bool
debugSQL bool
configPath string
dbpath string
cveDictionaryURL string
cvssScoreOver float64
httpProxy string
useYumPluginSecurity bool
useUnattendedUpgrades bool
// reporting
reportSlack bool
reportMail bool
}
// Name return subcommand name
func (*ScanCmd) Name() string { return "scan" }
// Synopsis return synopsis
func (*ScanCmd) Synopsis() string { return "Scan vulnerabilities." }
// Usage return usage
func (*ScanCmd) Usage() string {
return `scan:
scan
[-lang=en|ja]
[-config=/path/to/config.toml]
[-dbpath=/path/to/vuls.sqlite3]
[-cve-dictionary-url=http://127.0.0.1:1323]
[-cvss-over=7]
[-report-slack]
[-report-mail]
[-http-proxy=http://192.168.0.1:8080]
[-debug]
[-debug-sql]
`
}
// SetFlags set flag
func (p *ScanCmd) SetFlags(f *flag.FlagSet) {
f.StringVar(&p.lang, "lang", "en", "[en|ja]")
f.BoolVar(&p.debug, "debug", false, "debug mode")
f.BoolVar(&p.debugSQL, "debug-sql", false, "SQL debug mode")
defaultConfPath := os.Getenv("PWD") + "/config.toml"
f.StringVar(&p.configPath, "config", defaultConfPath, "/path/to/toml")
defaultDBPath := os.Getenv("PWD") + "/vuls.sqlite3"
f.StringVar(&p.dbpath, "dbpath", defaultDBPath, "/path/to/sqlite3")
defaultURL := "http://127.0.0.1:1323"
f.StringVar(
&p.cveDictionaryURL,
"cve-dictionary-url",
defaultURL,
"http://CVE.Dictionary")
f.Float64Var(
&p.cvssScoreOver,
"cvss-over",
0,
"-cvss-over=6.5 means reporting CVSS Score 6.5 and over (default: 0 (means report all))")
f.StringVar(
&p.httpProxy,
"http-proxy",
"",
"http://proxy-url:port (default: empty)",
)
f.BoolVar(&p.reportSlack, "report-slack", false, "Slack report")
f.BoolVar(&p.reportMail, "report-mail", false, "Email report")
f.BoolVar(
&p.useYumPluginSecurity,
"use-yum-plugin-security",
false,
"[Depricated] For CentOS 5. Scan by yum-plugin-security or not (use yum check-update by default)",
)
f.BoolVar(
&p.useUnattendedUpgrades,
"use-unattended-upgrades",
false,
"[Depricated] For Ubuntu. Scan by unattended-upgrades or not (use apt-get upgrade --dry-run by default)",
)
}
// Execute execute
func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
logrus.Infof("Begin scannig (config: %s)", p.configPath)
err := c.Load(p.configPath)
if err != nil {
logrus.Errorf("Error loading %s, %s", p.configPath, err)
return subcommands.ExitUsageError
}
target := make(map[string]c.ServerInfo)
for _, arg := range f.Args() {
found := false
for servername, info := range c.Conf.Servers {
if servername == arg {
target[servername] = info
found = true
break
}
}
if !found {
logrus.Errorf("%s is not in config", arg)
return subcommands.ExitUsageError
}
}
if 0 < len(f.Args()) {
c.Conf.Servers = target
}
c.Conf.Lang = p.lang
c.Conf.Debug = p.debug
c.Conf.DebugSQL = p.debugSQL
// logger
Log := util.NewCustomLogger(c.ServerInfo{})
// report
reports := []report.ResultWriter{
report.TextWriter{},
report.LogrusWriter{},
}
if p.reportSlack {
reports = append(reports, report.SlackWriter{})
}
if p.reportMail {
reports = append(reports, report.MailWriter{})
}
c.Conf.DBPath = p.dbpath
c.Conf.CveDictionaryURL = p.cveDictionaryURL
c.Conf.HTTPProxy = p.httpProxy
c.Conf.UseYumPluginSecurity = p.useYumPluginSecurity
c.Conf.UseUnattendedUpgrades = p.useUnattendedUpgrades
Log.Info("Validating Config...")
if !c.Conf.Validate() {
return subcommands.ExitUsageError
}
if ok, err := cveapi.CveClient.CheckHealth(); !ok {
Log.Errorf("CVE HTTP server is not running. %#v", cveapi.CveClient)
Log.Fatal(err)
return subcommands.ExitFailure
}
Log.Info("Detecting OS... ")
err = scan.InitServers(Log)
if err != nil {
Log.Errorf("Failed to init servers. err: %s", err)
return subcommands.ExitFailure
}
Log.Info("Scanning vulnerabilities... ")
if errs := scan.Scan(); 0 < len(errs) {
for _, e := range errs {
Log.Errorf("Failed to scan. err: %s.", e)
}
return subcommands.ExitFailure
}
scanResults, err := scan.GetScanResults()
if err != nil {
Log.Fatal(err)
return subcommands.ExitFailure
}
Log.Info("Reporting...")
filtered := scanResults.FilterByCvssOver()
for _, w := range reports {
if err := w.Write(filtered); err != nil {
Log.Fatalf("Failed to output report, err: %s", err)
return subcommands.ExitFailure
}
}
Log.Info("Insert to DB...")
if err := db.OpenDB(); err != nil {
Log.Errorf("Failed to open DB. datafile: %s, err: %s", c.Conf.DBPath, err)
return subcommands.ExitFailure
}
if err := db.MigrateDB(); err != nil {
Log.Errorf("Failed to migrate. err: %s", err)
return subcommands.ExitFailure
}
if err := db.Insert(scanResults); err != nil {
Log.Fatalf("Failed to insert. dbpath: %s, err: %s", c.Conf.DBPath, err)
return subcommands.ExitFailure
}
return subcommands.ExitSuccess
}

68
commands/tui.go Normal file
View File

@@ -0,0 +1,68 @@
/* Vuls - Vulnerability Scanner
Copyright (C) 2016 Future Architect, Inc. Japan.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package commands
import (
"flag"
"fmt"
"os"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/report"
"github.com/google/subcommands"
"golang.org/x/net/context"
)
// TuiCmd is Subcommand of host discovery mode
type TuiCmd struct {
lang string
debugSQL bool
dbpath string
}
// Name return subcommand name
func (*TuiCmd) Name() string { return "tui" }
// Synopsis return synopsis
func (*TuiCmd) Synopsis() string { return "Run Tui view to anayze vulnerabilites." }
// Usage return usage
func (*TuiCmd) Usage() string {
return `tui:
tui [-dbpath=/path/to/vuls.sqlite3]
`
}
// SetFlags set flag
func (p *TuiCmd) SetFlags(f *flag.FlagSet) {
// f.StringVar(&p.lang, "lang", "en", "[en|ja]")
f.BoolVar(&p.debugSQL, "debug-sql", false, "debug SQL")
defaultDBPath := os.Getenv("PWD") + "/vuls.sqlite3"
f.StringVar(&p.dbpath, "dbpath", defaultDBPath,
fmt.Sprintf("/path/to/sqlite3 (default: %s)", defaultDBPath))
}
// Execute execute
func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
c.Conf.Lang = "en"
c.Conf.DebugSQL = p.debugSQL
c.Conf.DBPath = p.dbpath
return report.RunTui()
}