feat(scan): WordPress Vulnerability Scan (core, plugin, theme) (#769)
https://github.com/future-architect/vuls/pull/769
This commit is contained in:
@@ -25,6 +25,7 @@ import (
|
||||
"time"
|
||||
|
||||
storage "github.com/Azure/azure-sdk-for-go/storage"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
c "github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
@@ -60,7 +61,7 @@ func (w AzureBlobWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
k := key + ".json"
|
||||
var b []byte
|
||||
if b, err = json.Marshal(r); err != nil {
|
||||
return fmt.Errorf("Failed to Marshal to JSON: %s", err)
|
||||
return xerrors.Errorf("Failed to Marshal to JSON: %w", err)
|
||||
}
|
||||
if err := createBlockBlob(cli, k, b); err != nil {
|
||||
return err
|
||||
@@ -87,7 +88,7 @@ func (w AzureBlobWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
k := key + ".xml"
|
||||
var b []byte
|
||||
if b, err = xml.Marshal(r); err != nil {
|
||||
return fmt.Errorf("Failed to Marshal to XML: %s", err)
|
||||
return xerrors.Errorf("Failed to Marshal to XML: %w", err)
|
||||
}
|
||||
allBytes := bytes.Join([][]byte{[]byte(xml.Header + vulsOpenTag), b, []byte(vulsCloseTag)}, []byte{})
|
||||
if err := createBlockBlob(cli, k, allBytes); err != nil {
|
||||
@@ -117,7 +118,7 @@ func CheckIfAzureContainerExists() error {
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return fmt.Errorf("Container not found. Container: %s", c.Conf.Azure.ContainerName)
|
||||
return xerrors.Errorf("Container not found. Container: %s", c.Conf.Azure.ContainerName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -142,7 +143,7 @@ func createBlockBlob(cli storage.BlobStorageClient, k string, b []byte) error {
|
||||
ref := cli.GetContainerReference(c.Conf.Azure.ContainerName)
|
||||
blob := ref.GetBlobReference(k)
|
||||
if err := blob.CreateBlockBlobFromReader(bytes.NewReader(b), nil); err != nil {
|
||||
return fmt.Errorf("Failed to upload data to %s/%s, %s",
|
||||
return xerrors.Errorf("Failed to upload data to %s/%s, err: %w",
|
||||
c.Conf.Azure.ContainerName, k, err)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/util"
|
||||
@@ -57,7 +58,7 @@ func (api cvedictClient) CheckHealth() error {
|
||||
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 request to CVE server. url: %s, errs: %v",
|
||||
return xerrors.Errorf("Failed to request to CVE server. url: %s, errs: %w",
|
||||
url, errs)
|
||||
}
|
||||
return nil
|
||||
@@ -73,7 +74,7 @@ func (api cvedictClient) FetchCveDetails(driver cvedb.DB, cveIDs []string) (cveD
|
||||
for _, cveID := range cveIDs {
|
||||
cveDetail, err := driver.Get(cveID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to fetch CVE. err: %s", err)
|
||||
return nil, xerrors.Errorf("Failed to fetch CVE. err: %w", err)
|
||||
}
|
||||
if len(cveDetail.CveID) == 0 {
|
||||
cveDetails = append(cveDetails, cve.CveDetail{
|
||||
@@ -132,12 +133,12 @@ func (api cvedictClient) FetchCveDetails(driver cvedb.DB, cveIDs []string) (cveD
|
||||
case err := <-errChan:
|
||||
errs = append(errs, err)
|
||||
case <-timeout:
|
||||
return nil, fmt.Errorf("Timeout Fetching CVE")
|
||||
return nil, xerrors.New("Timeout Fetching CVE")
|
||||
}
|
||||
}
|
||||
if len(errs) != 0 {
|
||||
return nil,
|
||||
fmt.Errorf("Failed to fetch CVE. err: %v", errs)
|
||||
xerrors.Errorf("Failed to fetch CVE. err: %w", errs)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -150,8 +151,8 @@ func (api cvedictClient) httpGet(key, url string, resChan chan<- response, errCh
|
||||
// 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 {
|
||||
return fmt.Errorf("HTTP GET error: %v, url: %s, resp: %v",
|
||||
errs, url, resp)
|
||||
return xerrors.Errorf("HTTP GET Error, url: %s, resp: %v, err: %w",
|
||||
url, resp, errs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -161,13 +162,12 @@ func (api cvedictClient) httpGet(key, url string, resChan chan<- response, errCh
|
||||
}
|
||||
err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify)
|
||||
if err != nil {
|
||||
errChan <- fmt.Errorf("HTTP Error %s", err)
|
||||
errChan <- xerrors.Errorf("HTTP Error: %w", err)
|
||||
return
|
||||
}
|
||||
cveDetail := cve.CveDetail{}
|
||||
if err := json.Unmarshal([]byte(body), &cveDetail); err != nil {
|
||||
errChan <- fmt.Errorf("Failed to Unmarshall. body: %s, err: %s",
|
||||
body, err)
|
||||
errChan <- xerrors.Errorf("Failed to Unmarshall. body: %s, err: %w", body, err)
|
||||
return
|
||||
}
|
||||
resChan <- response{
|
||||
@@ -203,7 +203,7 @@ func (api cvedictClient) httpPost(key, url string, query map[string]string) ([]c
|
||||
}
|
||||
resp, body, errs = req.End()
|
||||
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
|
||||
return fmt.Errorf("HTTP POST error: %v, url: %s, resp: %v", errs, url, resp)
|
||||
return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %w", url, resp, errs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -212,13 +212,13 @@ func (api cvedictClient) httpPost(key, url string, query map[string]string) ([]c
|
||||
}
|
||||
err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("HTTP Error %s", err)
|
||||
return nil, xerrors.Errorf("HTTP Error: %w", err)
|
||||
}
|
||||
|
||||
cveDetails := []cve.CveDetail{}
|
||||
if err := json.Unmarshal([]byte(body), &cveDetails); err != nil {
|
||||
return nil,
|
||||
fmt.Errorf("Failed to Unmarshall. body: %s, err: %s", body, err)
|
||||
xerrors.Errorf("Failed to Unmarshall. body: %s, err: %w", body, err)
|
||||
}
|
||||
return cveDetails, nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package report
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
@@ -10,6 +9,7 @@ import (
|
||||
cvedb "github.com/kotakanbe/go-cve-dictionary/db"
|
||||
ovaldb "github.com/kotakanbe/goval-dictionary/db"
|
||||
exploitdb "github.com/mozqnet/go-exploitdb/db"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// DBClient is a dictionarie's db client for reporting
|
||||
@@ -33,7 +33,7 @@ type DBClientConf struct {
|
||||
func NewDBClient(cnf DBClientConf) (dbclient *DBClient, locked bool, err error) {
|
||||
cveDriver, locked, err := NewCveDB(cnf)
|
||||
if locked {
|
||||
return nil, true, fmt.Errorf("CveDB is locked: %s",
|
||||
return nil, true, xerrors.Errorf("CveDB is locked: %s",
|
||||
cnf.OvalDictCnf.SQLite3Path)
|
||||
} else if err != nil {
|
||||
return nil, locked, err
|
||||
@@ -41,7 +41,7 @@ func NewDBClient(cnf DBClientConf) (dbclient *DBClient, locked bool, err error)
|
||||
|
||||
ovaldb, locked, err := NewOvalDB(cnf)
|
||||
if locked {
|
||||
return nil, true, fmt.Errorf("OvalDB is locked: %s",
|
||||
return nil, true, xerrors.Errorf("OvalDB is locked: %s",
|
||||
cnf.OvalDictCnf.SQLite3Path)
|
||||
} else if err != nil {
|
||||
util.Log.Warnf("Unable to use OvalDB: %s, err: %s",
|
||||
@@ -50,7 +50,7 @@ func NewDBClient(cnf DBClientConf) (dbclient *DBClient, locked bool, err error)
|
||||
|
||||
gostdb, locked, err := NewGostDB(cnf)
|
||||
if locked {
|
||||
return nil, true, fmt.Errorf("gostDB is locked: %s",
|
||||
return nil, true, xerrors.Errorf("gostDB is locked: %s",
|
||||
cnf.GostCnf.SQLite3Path)
|
||||
} else if err != nil {
|
||||
util.Log.Warnf("Unable to use gostDB: %s, err: %s",
|
||||
@@ -59,7 +59,7 @@ func NewDBClient(cnf DBClientConf) (dbclient *DBClient, locked bool, err error)
|
||||
|
||||
exploitdb, locked, err := NewExploitDB(cnf)
|
||||
if locked {
|
||||
return nil, true, fmt.Errorf("exploitDB is locked: %s",
|
||||
return nil, true, xerrors.Errorf("exploitDB is locked: %s",
|
||||
cnf.ExploitCnf.SQLite3Path)
|
||||
} else if err != nil {
|
||||
util.Log.Warnf("Unable to use exploitDB: %s, err: %s",
|
||||
@@ -88,7 +88,7 @@ func NewCveDB(cnf DBClientConf) (driver cvedb.DB, locked bool, err error) {
|
||||
util.Log.Debugf("Open cve-dictionary db (%s): %s", cnf.CveDictCnf.Type, path)
|
||||
driver, locked, err = cvedb.NewDB(cnf.CveDictCnf.Type, path, cnf.DebugSQL)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Failed to init CVE DB. err: %s, path: %s", err, path)
|
||||
err = xerrors.Errorf("Failed to init CVE DB. err: %w, path: %s", err, path)
|
||||
return nil, locked, err
|
||||
}
|
||||
return driver, false, nil
|
||||
@@ -112,7 +112,7 @@ func NewOvalDB(cnf DBClientConf) (driver ovaldb.DB, locked bool, err error) {
|
||||
util.Log.Debugf("Open oval-dictionary db (%s): %s", cnf.OvalDictCnf.Type, path)
|
||||
driver, locked, err = ovaldb.NewDB("", cnf.OvalDictCnf.Type, path, cnf.DebugSQL)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Failed to new OVAL DB. err: %s", err)
|
||||
err = xerrors.Errorf("Failed to new OVAL DB. err: %w", err)
|
||||
if locked {
|
||||
return nil, true, err
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// EMailWriter send mail
|
||||
@@ -108,7 +109,7 @@ func (e *emailSender) Send(subject, body string) (err error) {
|
||||
cc := strings.Join(emailConf.Cc[:], ", ")
|
||||
mailAddresses := append(emailConf.To, emailConf.Cc...)
|
||||
if _, err := mail.ParseAddressList(strings.Join(mailAddresses[:], ", ")); err != nil {
|
||||
return fmt.Errorf("Failed to parse email addresses: %s", err)
|
||||
return xerrors.Errorf("Failed to parse email addresses: %w", err)
|
||||
}
|
||||
|
||||
headers := make(map[string]string)
|
||||
@@ -141,7 +142,7 @@ func (e *emailSender) Send(subject, body string) (err error) {
|
||||
[]byte(message),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to send emails: %s", err)
|
||||
return xerrors.Errorf("Failed to send emails: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -153,7 +154,7 @@ func (e *emailSender) Send(subject, body string) (err error) {
|
||||
[]byte(message),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to send emails: %s", err)
|
||||
return xerrors.Errorf("Failed to send emails: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -22,10 +22,9 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
c "github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// HTTPRequestWriter writes results to HTTP request
|
||||
@@ -53,7 +52,7 @@ type HTTPResponseWriter struct {
|
||||
func (w HTTPResponseWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
res, err := json.Marshal(rs)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to marshal scah results")
|
||||
return xerrors.Errorf("Failed to marshal scah results: %w", err)
|
||||
}
|
||||
w.Writer.Header().Set("Content-Type", "application/json")
|
||||
_, err = w.Writer.Write(res)
|
||||
|
||||
@@ -21,13 +21,13 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
c "github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// LocalFileWriter writes results to a local file.
|
||||
@@ -40,8 +40,8 @@ func (w LocalFileWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
path := filepath.Join(w.CurrentDir, "summary.txt")
|
||||
text := formatOneLineSummary(rs...)
|
||||
if err := writeFile(path, []byte(text), 0600); err != nil {
|
||||
return fmt.Errorf(
|
||||
"Failed to write to file. path: %s, err: %s",
|
||||
return xerrors.Errorf(
|
||||
"Failed to write to file. path: %s, err: %w",
|
||||
path, err)
|
||||
}
|
||||
}
|
||||
@@ -60,15 +60,15 @@ func (w LocalFileWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
var b []byte
|
||||
if c.Conf.Debug {
|
||||
if b, err = json.MarshalIndent(r, "", " "); err != nil {
|
||||
return fmt.Errorf("Failed to Marshal to JSON: %s", err)
|
||||
return xerrors.Errorf("Failed to Marshal to JSON: %w", err)
|
||||
}
|
||||
} else {
|
||||
if b, err = json.Marshal(r); err != nil {
|
||||
return fmt.Errorf("Failed to Marshal to JSON: %s", err)
|
||||
return xerrors.Errorf("Failed to Marshal to JSON: %w", err)
|
||||
}
|
||||
}
|
||||
if err := writeFile(p, b, 0600); err != nil {
|
||||
return fmt.Errorf("Failed to write JSON. path: %s, err: %s", p, err)
|
||||
return xerrors.Errorf("Failed to write JSON. path: %s, err: %w", p, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ func (w LocalFileWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
|
||||
if err := writeFile(
|
||||
p, []byte(formatList(r)), 0600); err != nil {
|
||||
return fmt.Errorf(
|
||||
"Failed to write text files. path: %s, err: %s", p, err)
|
||||
return xerrors.Errorf(
|
||||
"Failed to write text files. path: %s, err: %w", p, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,8 +97,8 @@ func (w LocalFileWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
|
||||
if err := writeFile(
|
||||
p, []byte(formatFullPlainText(r)), 0600); err != nil {
|
||||
return fmt.Errorf(
|
||||
"Failed to write text files. path: %s, err: %s", p, err)
|
||||
return xerrors.Errorf(
|
||||
"Failed to write text files. path: %s, err: %w", p, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,11 +112,11 @@ func (w LocalFileWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
|
||||
var b []byte
|
||||
if b, err = xml.Marshal(r); err != nil {
|
||||
return fmt.Errorf("Failed to Marshal to XML: %s", err)
|
||||
return xerrors.Errorf("Failed to Marshal to XML: %w", err)
|
||||
}
|
||||
allBytes := bytes.Join([][]byte{[]byte(xml.Header + vulsOpenTag), b, []byte(vulsCloseTag)}, []byte{})
|
||||
if err := writeFile(p, allBytes, 0600); err != nil {
|
||||
return fmt.Errorf("Failed to write XML. path: %s, err: %s", p, err)
|
||||
return xerrors.Errorf("Failed to write XML. path: %s, err: %w", p, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,13 @@ import (
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/oval"
|
||||
"github.com/future-architect/vuls/util"
|
||||
"github.com/future-architect/vuls/wordpress"
|
||||
"github.com/hashicorp/uuid"
|
||||
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"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -69,7 +70,7 @@ func FillCveInfos(dbclient DBClient, rs []models.ScanResult, dir string) ([]mode
|
||||
if owaspDCXMLPath != "" {
|
||||
cpes, err := parser.Parse(owaspDCXMLPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read OWASP Dependency Check XML: %s, %s, %s",
|
||||
return nil, xerrors.Errorf("Failed to read OWASP Dependency Check XML on %s, `%s`, err: %w",
|
||||
r.ServerName, owaspDCXMLPath, err)
|
||||
}
|
||||
cpeURIs = append(cpeURIs, cpes...)
|
||||
@@ -82,7 +83,7 @@ func FillCveInfos(dbclient DBClient, rs []models.ScanResult, dir string) ([]mode
|
||||
if owaspDCXMLPath != "" {
|
||||
cpes, err := parser.Parse(owaspDCXMLPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read OWASP Dependency Check XML: %s, %s, %s",
|
||||
return nil, xerrors.Errorf("Failed to read OWASP Dependency Check XML on %s, `%s`, err: %w",
|
||||
r.ServerInfo(), owaspDCXMLPath, err)
|
||||
}
|
||||
cpeURIs = append(cpeURIs, cpes...)
|
||||
@@ -91,8 +92,16 @@ func FillCveInfos(dbclient DBClient, rs []models.ScanResult, dir string) ([]mode
|
||||
}
|
||||
}
|
||||
|
||||
// Integrations
|
||||
githubInts := GithubSecurityAlerts(c.Conf.Servers[r.ServerName].GitHubRepos)
|
||||
if err := FillCveInfo(dbclient, &r, cpeURIs, githubInts); err != nil {
|
||||
|
||||
wpOpt := WordPressOption{c.Conf.Servers[r.ServerName].WordPress.WPVulnDBToken}
|
||||
|
||||
if err := FillCveInfo(dbclient,
|
||||
&r,
|
||||
cpeURIs,
|
||||
githubInts,
|
||||
wpOpt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.Lang = c.Conf.Lang
|
||||
@@ -105,7 +114,7 @@ func FillCveInfos(dbclient DBClient, rs []models.ScanResult, dir string) ([]mode
|
||||
r.ServerName: c.Conf.Servers[r.ServerName],
|
||||
}
|
||||
if err := overwriteJSONFile(dir, r); err != nil {
|
||||
return nil, fmt.Errorf("Failed to write JSON: %s", err)
|
||||
return nil, xerrors.Errorf("Failed to write JSON: %w", err)
|
||||
}
|
||||
filledResults = append(filledResults, r)
|
||||
} else {
|
||||
@@ -139,6 +148,7 @@ func FillCveInfos(dbclient DBClient, rs []models.ScanResult, dir string) ([]mode
|
||||
r = r.FilterIgnoreCves()
|
||||
r = r.FilterUnfixed()
|
||||
r = r.FilterIgnorePkgs()
|
||||
r = r.FilterInactiveWordPressLibs()
|
||||
if c.Conf.IgnoreUnscoredCves {
|
||||
r.ScannedCves = r.ScannedCves.FindScoredVulns()
|
||||
}
|
||||
@@ -153,7 +163,7 @@ func FillCveInfo(dbclient DBClient, r *models.ScanResult, cpeURIs []string, inte
|
||||
|
||||
nCVEs, err := FillWithOval(dbclient.OvalDB, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to fill with OVAL: %s", err)
|
||||
return xerrors.Errorf("Failed to fill with OVAL: %w", err)
|
||||
}
|
||||
util.Log.Infof("%s: %d CVEs are detected with OVAL",
|
||||
r.FormatServerName(), nCVEs)
|
||||
@@ -169,11 +179,11 @@ func FillCveInfo(dbclient DBClient, r *models.ScanResult, cpeURIs []string, inte
|
||||
|
||||
nCVEs, err = fillVulnByCpeURIs(dbclient.CveDB, r, cpeURIs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to detect vulns of %s: %s", cpeURIs, err)
|
||||
return xerrors.Errorf("Failed to detect vulns of `%s`: %w", cpeURIs, err)
|
||||
}
|
||||
util.Log.Infof("%s: %d CVEs are detected with CPE", r.FormatServerName(), nCVEs)
|
||||
|
||||
ints := &ints{}
|
||||
ints := &integrationResults{}
|
||||
for _, o := range integrations {
|
||||
if err = o.apply(r, ints); err != nil {
|
||||
return err
|
||||
@@ -183,20 +193,20 @@ func FillCveInfo(dbclient DBClient, r *models.ScanResult, cpeURIs []string, inte
|
||||
|
||||
nCVEs, err = FillWithGost(dbclient.GostDB, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to fill with gost: %s", err)
|
||||
return xerrors.Errorf("Failed to fill with gost: %w", err)
|
||||
}
|
||||
util.Log.Infof("%s: %d unfixed CVEs are detected with gost",
|
||||
r.FormatServerName(), nCVEs)
|
||||
|
||||
util.Log.Infof("Fill CVE detailed information with CVE-DB")
|
||||
if err := fillCveDetail(dbclient.CveDB, r); err != nil {
|
||||
return fmt.Errorf("Failed to fill with CVE: %s", err)
|
||||
return xerrors.Errorf("Failed to fill with CVE: %w", 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)
|
||||
return xerrors.Errorf("Failed to fill with exploit: %w", err)
|
||||
}
|
||||
util.Log.Infof("%s: %d exploits are detected",
|
||||
r.FormatServerName(), nExploitCve)
|
||||
@@ -280,9 +290,9 @@ func FillWithOval(driver ovaldb.DB, r *models.ScanResult) (nCVEs int, err error)
|
||||
return 0, nil
|
||||
default:
|
||||
if r.Family == "" {
|
||||
return 0, fmt.Errorf("Probably an error occurred during scanning. Check the error message")
|
||||
return 0, xerrors.New("Probably an error occurred during scanning. Check the error message")
|
||||
}
|
||||
return 0, fmt.Errorf("OVAL for %s is not implemented yet", r.Family)
|
||||
return 0, xerrors.Errorf("OVAL for %s is not implemented yet", r.Family)
|
||||
}
|
||||
|
||||
if !c.Conf.OvalDict.IsFetchViaHTTP() {
|
||||
@@ -290,7 +300,7 @@ func FillWithOval(driver ovaldb.DB, r *models.ScanResult) (nCVEs int, err error)
|
||||
return 0, nil
|
||||
}
|
||||
if err = driver.NewOvalDB(ovalFamily); err != nil {
|
||||
return 0, fmt.Errorf("Failed to New Oval DB. err: %s", err)
|
||||
return 0, xerrors.Errorf("Failed to New Oval DB. err: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,13 +366,14 @@ func fillVulnByCpeURIs(driver cvedb.DB, r *models.ScanResult, cpeURIs []string)
|
||||
return nCVEs, nil
|
||||
}
|
||||
|
||||
type ints struct {
|
||||
type integrationResults struct {
|
||||
GithubAlertsCveCounts int
|
||||
WordPressCveCounts int
|
||||
}
|
||||
|
||||
// Integration is integration of vuls report
|
||||
type Integration interface {
|
||||
apply(*models.ScanResult, *ints) error
|
||||
apply(*models.ScanResult, *integrationResults) error
|
||||
}
|
||||
|
||||
// GithubSecurityAlerts :
|
||||
@@ -377,14 +388,15 @@ type GithubSecurityAlertOption struct {
|
||||
GithubConfs map[string]config.GitHubConf
|
||||
}
|
||||
|
||||
func (g GithubSecurityAlertOption) apply(r *models.ScanResult, ints *ints) (err error) {
|
||||
// https://help.github.com/articles/about-security-alerts-for-vulnerable-dependencies/
|
||||
func (g GithubSecurityAlertOption) apply(r *models.ScanResult, ints *integrationResults) (err error) {
|
||||
var nCVEs int
|
||||
for ownerRepo, setting := range g.GithubConfs {
|
||||
ss := strings.Split(ownerRepo, "/")
|
||||
owner, repo := ss[0], ss[1]
|
||||
n, err := github.FillGitHubSecurityAlerts(r, owner, repo, setting.Token)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to access GitHub Security Alerts")
|
||||
return xerrors.Errorf("Failed to access GitHub Security Alerts: %w", err)
|
||||
}
|
||||
nCVEs += n
|
||||
}
|
||||
@@ -392,19 +404,21 @@ func (g GithubSecurityAlertOption) apply(r *models.ScanResult, ints *ints) (err
|
||||
return nil
|
||||
}
|
||||
|
||||
// https://help.github.com/articles/about-security-alerts-for-vulnerable-dependencies/
|
||||
func fillGitHubSecurityAlerts(r *models.ScanResult) (nCVEs int, err error) {
|
||||
repos := c.Conf.Servers[r.ServerName].GitHubRepos
|
||||
for ownerRepo, setting := range repos {
|
||||
ss := strings.Split(ownerRepo, "/")
|
||||
owner, repo := ss[0], ss[1]
|
||||
n, err := github.FillGitHubSecurityAlerts(r, owner, repo, setting.Token)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
nCVEs += n
|
||||
// WordPressOption :
|
||||
type WordPressOption struct {
|
||||
token string
|
||||
}
|
||||
|
||||
func (g WordPressOption) apply(r *models.ScanResult, ints *integrationResults) (err error) {
|
||||
if g.token == "" {
|
||||
return nil
|
||||
}
|
||||
return nCVEs, nil
|
||||
n, err := wordpress.FillWordPress(r, g.token)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("Failed to fetch from WPVulnDB. Check the WPVulnDBToken in config.toml. err: %w", err)
|
||||
}
|
||||
ints.WordPressCveCounts = n
|
||||
return nil
|
||||
}
|
||||
|
||||
func fillCweDict(r *models.ScanResult) {
|
||||
@@ -420,9 +434,6 @@ func fillCweDict(r *models.ScanResult) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO check the format of CWEID, clean CWEID
|
||||
// JVN, NVD XML, JSON, OVALs
|
||||
|
||||
dict := map[string]models.CweDictEntry{}
|
||||
for id := range uniqCweIDMap {
|
||||
entry := models.CweDictEntry{}
|
||||
@@ -638,21 +649,21 @@ func EnsureUUIDs(configPath string, results models.ScanResults) error {
|
||||
// rename the current config.toml to config.toml.bak
|
||||
info, err := os.Lstat(configPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to lstat %s: %s", configPath, err)
|
||||
return xerrors.Errorf("Failed to lstat %s: %w", configPath, err)
|
||||
}
|
||||
realPath := configPath
|
||||
if info.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
if realPath, err = os.Readlink(configPath); err != nil {
|
||||
return fmt.Errorf("Failed to Read link %s: %s", configPath, err)
|
||||
return xerrors.Errorf("Failed to Read link %s: %w", configPath, err)
|
||||
}
|
||||
}
|
||||
if err := os.Rename(realPath, realPath+".bak"); err != nil {
|
||||
return fmt.Errorf("Failed to rename %s: %s", configPath, err)
|
||||
return xerrors.Errorf("Failed to rename %s: %w", configPath, err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := toml.NewEncoder(&buf).Encode(c); err != nil {
|
||||
return fmt.Errorf("Failed to encode to toml: %s", err)
|
||||
return xerrors.Errorf("Failed to encode to toml: %w", err)
|
||||
}
|
||||
str := strings.Replace(buf.String(), "\n [", "\n\n [", -1)
|
||||
str = fmt.Sprintf("%s\n\n%s",
|
||||
|
||||
13
report/s3.go
13
report/s3.go
@@ -31,6 +31,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
c "github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
@@ -75,7 +76,7 @@ func (w S3Writer) Write(rs ...models.ScanResult) (err error) {
|
||||
k := key + ".json"
|
||||
var b []byte
|
||||
if b, err = json.Marshal(r); err != nil {
|
||||
return fmt.Errorf("Failed to Marshal to JSON: %s", err)
|
||||
return xerrors.Errorf("Failed to Marshal to JSON: %w", err)
|
||||
}
|
||||
if err := putObject(svc, k, b); err != nil {
|
||||
return err
|
||||
@@ -102,7 +103,7 @@ func (w S3Writer) Write(rs ...models.ScanResult) (err error) {
|
||||
k := key + ".xml"
|
||||
var b []byte
|
||||
if b, err = xml.Marshal(r); err != nil {
|
||||
return fmt.Errorf("Failed to Marshal to XML: %s", err)
|
||||
return xerrors.Errorf("Failed to Marshal to XML: %w", err)
|
||||
}
|
||||
allBytes := bytes.Join([][]byte{[]byte(xml.Header + vulsOpenTag), b, []byte(vulsCloseTag)}, []byte{})
|
||||
if err := putObject(svc, k, allBytes); err != nil {
|
||||
@@ -118,8 +119,8 @@ func CheckIfBucketExists() error {
|
||||
svc := getS3()
|
||||
result, err := svc.ListBuckets(&s3.ListBucketsInput{})
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Failed to list buckets. err: %s, profile: %s, region: %s",
|
||||
return xerrors.Errorf(
|
||||
"Failed to list buckets. err: %w, profile: %s, region: %s",
|
||||
err, c.Conf.AWS.Profile, c.Conf.AWS.Region)
|
||||
}
|
||||
|
||||
@@ -131,7 +132,7 @@ func CheckIfBucketExists() error {
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return fmt.Errorf(
|
||||
return xerrors.Errorf(
|
||||
"Failed to find the buckets. profile: %s, region: %s, bucket: %s",
|
||||
c.Conf.AWS.Profile, c.Conf.AWS.Region, c.Conf.AWS.S3Bucket)
|
||||
}
|
||||
@@ -158,7 +159,7 @@ func putObject(svc *s3.S3, k string, b []byte) error {
|
||||
}
|
||||
|
||||
if _, err := svc.PutObject(putObjectInput); err != nil {
|
||||
return fmt.Errorf("Failed to upload data to %s/%s, %s",
|
||||
return xerrors.Errorf("Failed to upload data to %s/%s, err: %w",
|
||||
c.Conf.AWS.S3Bucket, k, err)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
c "github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// SaasWriter writes results to SaaS
|
||||
@@ -80,7 +81,7 @@ func (w SaasWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
|
||||
var body []byte
|
||||
if body, err = json.Marshal(payload); err != nil {
|
||||
return fmt.Errorf("Failed to Marshal to JSON: %s", err)
|
||||
return xerrors.Errorf("Failed to Marshal to JSON: %w", err)
|
||||
}
|
||||
|
||||
var req *http.Request
|
||||
@@ -109,7 +110,7 @@ func (w SaasWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("Failed to get Credential. Request JSON : %s,", string(body))
|
||||
return xerrors.Errorf("Failed to get Credential. Request JSON : %s,", string(body))
|
||||
}
|
||||
|
||||
var t []byte
|
||||
@@ -119,7 +120,7 @@ func (w SaasWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
|
||||
var tempCredential TempCredential
|
||||
if err = json.Unmarshal(t, &tempCredential); err != nil {
|
||||
return fmt.Errorf("Failed to unmarshal saas credential file. err : %s", err)
|
||||
return xerrors.Errorf("Failed to unmarshal saas credential file. err : %s", err)
|
||||
}
|
||||
|
||||
credential := credentials.NewStaticCredentialsFromCreds(credentials.Value{
|
||||
@@ -133,7 +134,7 @@ func (w SaasWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
Credentials: credential,
|
||||
Region: aws.String("ap-northeast-1"),
|
||||
}); err != nil {
|
||||
return fmt.Errorf("Failed to new aws session. err : %s", err)
|
||||
return xerrors.Errorf("Failed to new aws session. err: %w", err)
|
||||
}
|
||||
|
||||
svc := s3.New(sess)
|
||||
@@ -141,7 +142,7 @@ func (w SaasWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
s3Key := renameKeyNameUTC(r.ScannedAt, r.ServerUUID, r.Container)
|
||||
var b []byte
|
||||
if b, err = json.Marshal(r); err != nil {
|
||||
return fmt.Errorf("Failed to Marshal to JSON: %s", err)
|
||||
return xerrors.Errorf("Failed to Marshal to JSON: %w", err)
|
||||
}
|
||||
util.Log.Infof("Uploading...: ServerName: %s, ", r.ServerName)
|
||||
putObjectInput := &s3.PutObjectInput{
|
||||
@@ -151,7 +152,7 @@ func (w SaasWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
}
|
||||
|
||||
if _, err := svc.PutObject(putObjectInput); err != nil {
|
||||
return fmt.Errorf("Failed to upload data to %s/%s, %s",
|
||||
return xerrors.Errorf("Failed to upload data to %s/%s, err: %w",
|
||||
tempCredential.S3Bucket, s3Key, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
"github.com/nlopes/slack"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type field struct {
|
||||
@@ -155,9 +156,9 @@ func send(msg message) error {
|
||||
if count == retryMax {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf(
|
||||
"HTTP POST error: %v, url: %s, resp: %v, body: %s",
|
||||
errs, conf.HookURL, resp, body)
|
||||
return xerrors.Errorf(
|
||||
"HTTP POST error. url: %s, resp: %v, body: %s, err: %w",
|
||||
conf.HookURL, resp, body, errs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -167,10 +168,10 @@ func send(msg message) error {
|
||||
}
|
||||
boff := backoff.NewExponentialBackOff()
|
||||
if err := backoff.RetryNotify(f, boff, notify); err != nil {
|
||||
return fmt.Errorf("HTTP error: %s", err)
|
||||
return xerrors.Errorf("HTTP error: %w", err)
|
||||
}
|
||||
if count == retryMax {
|
||||
return fmt.Errorf("Retry count exceeded")
|
||||
return xerrors.New("Retry count exceeded")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -202,39 +203,44 @@ func msgText(r models.ScanResult) string {
|
||||
func toSlackAttachments(r models.ScanResult) (attaches []slack.Attachment) {
|
||||
vinfos := r.ScannedCves.ToSortedSlice()
|
||||
for _, vinfo := range vinfos {
|
||||
curent := []string{}
|
||||
|
||||
installed, candidate := []string{}, []string{}
|
||||
for _, affected := range vinfo.AffectedPackages {
|
||||
if p, ok := r.Packages[affected.Name]; ok {
|
||||
curent = append(curent,
|
||||
installed = append(installed,
|
||||
fmt.Sprintf("%s-%s", p.Name, p.FormatVer()))
|
||||
} else {
|
||||
curent = append(curent, affected.Name)
|
||||
installed = append(installed, affected.Name)
|
||||
}
|
||||
}
|
||||
for _, n := range vinfo.CpeURIs {
|
||||
curent = append(curent, n)
|
||||
}
|
||||
for _, n := range vinfo.GitHubSecurityAlerts {
|
||||
curent = append(curent, n.PackageName)
|
||||
}
|
||||
|
||||
new := []string{}
|
||||
for _, affected := range vinfo.AffectedPackages {
|
||||
if p, ok := r.Packages[affected.Name]; ok {
|
||||
if affected.NotFixedYet {
|
||||
new = append(new, "Not Fixed Yet")
|
||||
candidate = append(candidate, "Not Fixed Yet")
|
||||
} else {
|
||||
new = append(new, p.FormatNewVer())
|
||||
candidate = append(candidate, p.FormatNewVer())
|
||||
}
|
||||
} else {
|
||||
new = append(new, "?")
|
||||
candidate = append(candidate, "?")
|
||||
}
|
||||
}
|
||||
for range vinfo.CpeURIs {
|
||||
new = append(new, "?")
|
||||
|
||||
for _, n := range vinfo.CpeURIs {
|
||||
installed = append(installed, n)
|
||||
candidate = append(candidate, "?")
|
||||
}
|
||||
for range vinfo.GitHubSecurityAlerts {
|
||||
new = append(new, "?")
|
||||
for _, n := range vinfo.GitHubSecurityAlerts {
|
||||
installed = append(installed, n.PackageName)
|
||||
candidate = append(candidate, "?")
|
||||
}
|
||||
|
||||
for _, wp := range vinfo.WpPackageFixStats {
|
||||
if p, ok := r.WordPressPackages.Find(wp.Name); ok {
|
||||
installed = append(installed, fmt.Sprintf("%s-%s", wp.Name, p.Version))
|
||||
candidate = append(candidate, wp.FixedIn)
|
||||
} else {
|
||||
installed = append(installed, wp.Name)
|
||||
candidate = append(candidate, "?")
|
||||
}
|
||||
}
|
||||
|
||||
a := slack.Attachment{
|
||||
@@ -246,12 +252,12 @@ func toSlackAttachments(r models.ScanResult) (attaches []slack.Attachment) {
|
||||
{
|
||||
// Title: "Current Package/CPE",
|
||||
Title: "Installed",
|
||||
Value: strings.Join(curent, "\n"),
|
||||
Value: strings.Join(installed, "\n"),
|
||||
Short: true,
|
||||
},
|
||||
{
|
||||
Title: "Candidate",
|
||||
Value: strings.Join(new, "\n"),
|
||||
Value: strings.Join(candidate, "\n"),
|
||||
Short: true,
|
||||
},
|
||||
},
|
||||
@@ -269,7 +275,7 @@ func cvssColor(cvssScore float64) string {
|
||||
return "danger"
|
||||
case 4 <= cvssScore && cvssScore < 7:
|
||||
return "warning"
|
||||
case cvssScore < 0:
|
||||
case cvssScore == 0:
|
||||
return "#C0C0C0"
|
||||
default:
|
||||
return "good"
|
||||
|
||||
@@ -22,8 +22,7 @@ import (
|
||||
"strings"
|
||||
|
||||
syslog "github.com/RackSec/srslog"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
@@ -40,7 +39,7 @@ func (w SyslogWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
|
||||
sysLog, err := syslog.Dial(conf.Protocol, raddr, severity|facility, conf.Tag)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to initialize syslog client")
|
||||
return xerrors.Errorf("Failed to initialize syslog client: %w", err)
|
||||
}
|
||||
|
||||
for _, r := range rs {
|
||||
|
||||
@@ -22,15 +22,15 @@ func TestSyslogWriterEncodeSyslog(t *testing.T) {
|
||||
IPv4Addrs: []string{"192.168.0.1", "10.0.2.15"},
|
||||
ScannedCves: models.VulnInfos{
|
||||
"CVE-2017-0001": models.VulnInfo{
|
||||
AffectedPackages: models.PackageStatuses{
|
||||
models.PackageStatus{Name: "pkg1"},
|
||||
models.PackageStatus{Name: "pkg2"},
|
||||
AffectedPackages: models.PackageFixStatuses{
|
||||
models.PackageFixStatus{Name: "pkg1"},
|
||||
models.PackageFixStatus{Name: "pkg2"},
|
||||
},
|
||||
},
|
||||
"CVE-2017-0002": models.VulnInfo{
|
||||
AffectedPackages: models.PackageStatuses{
|
||||
models.PackageStatus{Name: "pkg3"},
|
||||
models.PackageStatus{Name: "pkg4"},
|
||||
AffectedPackages: models.PackageFixStatuses{
|
||||
models.PackageFixStatus{Name: "pkg3"},
|
||||
models.PackageFixStatus{Name: "pkg4"},
|
||||
},
|
||||
CveContents: models.CveContents{
|
||||
models.NvdXML: models.CveContent{
|
||||
@@ -57,8 +57,8 @@ func TestSyslogWriterEncodeSyslog(t *testing.T) {
|
||||
IPv6Addrs: []string{"2001:0DB8::1"},
|
||||
ScannedCves: models.VulnInfos{
|
||||
"CVE-2017-0003": models.VulnInfo{
|
||||
AffectedPackages: models.PackageStatuses{
|
||||
models.PackageStatus{Name: "pkg5"},
|
||||
AffectedPackages: models.PackageFixStatuses{
|
||||
models.PackageFixStatus{Name: "pkg5"},
|
||||
},
|
||||
CveContents: models.CveContents{
|
||||
models.RedHat: models.CveContent{
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// TelegramWriter sends report to Telegram
|
||||
@@ -73,5 +74,5 @@ func checkResponse(r *http.Response) error {
|
||||
if c := r.StatusCode; 200 <= c && c <= 299 {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("API call to %s failed: %s", r.Request.URL.String(), r.Status)
|
||||
return xerrors.Errorf("API call to %s failed: %s", r.Request.URL.String(), r.Status)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/future-architect/vuls/alert"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
@@ -581,7 +582,7 @@ func setSideLayout(g *gocui.Gui) error {
|
||||
fmt.Fprintln(v, result.ServerInfoTui())
|
||||
}
|
||||
if len(scanResults) == 0 {
|
||||
return fmt.Errorf("No scan results")
|
||||
return xerrors.New("No scan results")
|
||||
}
|
||||
currentScanResult = scanResults[0]
|
||||
vinfos = scanResults[0].ScannedCves.ToSortedSlice()
|
||||
@@ -634,9 +635,10 @@ func summaryLines(r models.ScanResult) string {
|
||||
cvssScore = fmt.Sprintf("| %4.1f", max)
|
||||
}
|
||||
|
||||
packname := vinfo.AffectedPackages.FormatTuiSummary()
|
||||
packname += strings.Join(vinfo.CpeURIs, ", ")
|
||||
packname += vinfo.GitHubSecurityAlerts.String()
|
||||
pkgNames := vinfo.AffectedPackages.Names()
|
||||
pkgNames = append(pkgNames, vinfo.CpeURIs...)
|
||||
pkgNames = append(pkgNames, vinfo.GitHubSecurityAlerts.Names()...)
|
||||
pkgNames = append(pkgNames, vinfo.WpPackageFixStats.Names()...)
|
||||
|
||||
alert := " "
|
||||
if vinfo.AlertDict.HasAlert() {
|
||||
@@ -648,9 +650,9 @@ func summaryLines(r models.ScanResult) string {
|
||||
fmt.Sprintf(indexFormat, i+1),
|
||||
alert + vinfo.CveID,
|
||||
cvssScore + " |",
|
||||
fmt.Sprintf("%8s |", vinfo.AttackVector()),
|
||||
fmt.Sprintf("%1s |", vinfo.AttackVector()),
|
||||
fmt.Sprintf("%7s |", vinfo.PatchStatus(r.Packages)),
|
||||
packname,
|
||||
strings.Join(pkgNames, ", "),
|
||||
}
|
||||
icols := make([]interface{}, len(cols))
|
||||
for j := range cols {
|
||||
@@ -747,6 +749,22 @@ func setChangelogLayout(g *gocui.Gui) error {
|
||||
lines = append(lines, "* "+alert.PackageName)
|
||||
}
|
||||
|
||||
r := currentScanResult
|
||||
for _, wp := range vinfo.WpPackageFixStats {
|
||||
if p, ok := r.WordPressPackages.Find(wp.Name); ok {
|
||||
if p.Type == models.WPCore {
|
||||
lines = append(lines, fmt.Sprintf("* %s-%s, FixedIn: %s",
|
||||
wp.Name, p.Version, wp.FixedIn))
|
||||
} else {
|
||||
lines = append(lines,
|
||||
fmt.Sprintf("* %s-%s, Update: %s, FixedIn: %s, %s",
|
||||
wp.Name, p.Version, p.Update, wp.FixedIn, p.Status))
|
||||
}
|
||||
} else {
|
||||
lines = append(lines, fmt.Sprintf("* %s", wp.Name))
|
||||
}
|
||||
}
|
||||
|
||||
for _, adv := range vinfo.DistroAdvisories {
|
||||
lines = append(lines, "\n",
|
||||
"Advisories",
|
||||
@@ -846,10 +864,13 @@ func detailLines() (string, error) {
|
||||
}
|
||||
|
||||
vinfo := vinfos[currentVinfo]
|
||||
links := []string{vinfo.CveContents.SourceLinks(
|
||||
config.Conf.Lang, r.Family, vinfo.CveID)[0].Value,
|
||||
vinfo.Cvss2CalcURL(),
|
||||
vinfo.Cvss3CalcURL()}
|
||||
links := []string{}
|
||||
if strings.HasPrefix(vinfo.CveID, "CVE-") {
|
||||
links = append(links, vinfo.CveContents.SourceLinks(
|
||||
config.Conf.Lang, r.Family, vinfo.CveID)[0].Value,
|
||||
vinfo.Cvss2CalcURL(),
|
||||
vinfo.Cvss3CalcURL())
|
||||
}
|
||||
for _, url := range vinfo.VendorLinks(r.Family) {
|
||||
links = append(links, url)
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
"github.com/future-architect/vuls/util"
|
||||
"github.com/gosuri/uitable"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
const maxColWidth = 100
|
||||
@@ -121,17 +122,23 @@ No CVE-IDs are found in updatable packages.
|
||||
exploits = " Y"
|
||||
}
|
||||
|
||||
link := ""
|
||||
if strings.HasPrefix(vinfo.CveID, "CVE-") {
|
||||
link = fmt.Sprintf("https://nvd.nist.gov/vuln/detail/%s", vinfo.CveID)
|
||||
} else if strings.HasPrefix(vinfo.CveID, "WPVDBID-") {
|
||||
link = fmt.Sprintf("https://wpvulndb.com/vulnerabilities/%s", strings.TrimPrefix(vinfo.CveID, "WPVDBID-"))
|
||||
}
|
||||
|
||||
data = append(data, []string{
|
||||
vinfo.CveID,
|
||||
fmt.Sprintf("%7s", vinfo.PatchStatus(r.Packages)),
|
||||
vinfo.AlertDict.FormatSource(),
|
||||
fmt.Sprintf("%4.1f", max),
|
||||
// fmt.Sprintf("%4.1f", v2max),
|
||||
// fmt.Sprintf("%4.1f", v3max),
|
||||
fmt.Sprintf("%8s", vinfo.AttackVector()),
|
||||
fmt.Sprintf("%7s", vinfo.PatchStatus(r.Packages)),
|
||||
// packname,
|
||||
fmt.Sprintf("https://nvd.nist.gov/vuln/detail/%s", vinfo.CveID),
|
||||
fmt.Sprintf("%2s", vinfo.AttackVector()),
|
||||
exploits,
|
||||
link,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -139,15 +146,14 @@ No CVE-IDs are found in updatable packages.
|
||||
table := tablewriter.NewWriter(&b)
|
||||
table.SetHeader([]string{
|
||||
"CVE-ID",
|
||||
"Fixed",
|
||||
"CERT",
|
||||
"CVSS",
|
||||
// "v3",
|
||||
// "v2",
|
||||
"Attack",
|
||||
"Fixed",
|
||||
// "Pkg",
|
||||
"AV",
|
||||
"PoC",
|
||||
"NVD",
|
||||
"Exploit",
|
||||
})
|
||||
table.SetBorder(true)
|
||||
table.AppendBulk(data)
|
||||
@@ -243,19 +249,37 @@ No CVE-IDs are found in updatable packages.
|
||||
data = append(data, []string{"GitHub", alert.PackageName})
|
||||
}
|
||||
|
||||
for _, wp := range vuln.WpPackageFixStats {
|
||||
if p, ok := r.WordPressPackages.Find(wp.Name); ok {
|
||||
if p.Type == models.WPCore {
|
||||
data = append(data, []string{"WordPress",
|
||||
fmt.Sprintf("%s-%s, FixedIn: %s", wp.Name, p.Version, wp.FixedIn)})
|
||||
} else {
|
||||
data = append(data, []string{"WordPress",
|
||||
fmt.Sprintf("%s-%s, Update: %s, FixedIn: %s, %s",
|
||||
wp.Name, p.Version, p.Update, wp.FixedIn, p.Status)})
|
||||
}
|
||||
} else {
|
||||
data = append(data, []string{"WordPress",
|
||||
fmt.Sprintf("%s", wp.Name)})
|
||||
}
|
||||
}
|
||||
|
||||
for _, confidence := range vuln.Confidences {
|
||||
data = append(data, []string{"Confidence", confidence.String()})
|
||||
}
|
||||
|
||||
links := vuln.CveContents.SourceLinks(
|
||||
config.Conf.Lang, r.Family, vuln.CveID)
|
||||
data = append(data, []string{"Source", links[0].Value})
|
||||
if strings.HasPrefix(vuln.CveID, "CVE-") {
|
||||
links := vuln.CveContents.SourceLinks(
|
||||
config.Conf.Lang, r.Family, vuln.CveID)
|
||||
data = append(data, []string{"Source", links[0].Value})
|
||||
|
||||
if 0 < len(vuln.Cvss2Scores(r.Family)) {
|
||||
data = append(data, []string{"CVSSv2 Calc", vuln.Cvss2CalcURL()})
|
||||
}
|
||||
if 0 < len(vuln.Cvss3Scores()) {
|
||||
data = append(data, []string{"CVSSv3 Calc", vuln.Cvss3CalcURL()})
|
||||
if 0 < len(vuln.Cvss2Scores(r.Family)) {
|
||||
data = append(data, []string{"CVSSv2 Calc", vuln.Cvss2CalcURL()})
|
||||
}
|
||||
if 0 < len(vuln.Cvss3Scores()) {
|
||||
data = append(data, []string{"CVSSv3 Calc", vuln.Cvss3CalcURL()})
|
||||
}
|
||||
}
|
||||
|
||||
vlinks := vuln.VendorLinks(r.Family)
|
||||
@@ -292,7 +316,7 @@ No CVE-IDs are found in updatable packages.
|
||||
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetHeader([]string{
|
||||
vuln.CveID,
|
||||
"",
|
||||
vuln.PatchStatus(r.Packages),
|
||||
})
|
||||
table.SetBorder(true)
|
||||
table.AppendBulk(data)
|
||||
@@ -353,7 +377,7 @@ func overwriteJSONFile(dir string, r models.ScanResult) error {
|
||||
config.Conf.Diff = false
|
||||
w := LocalFileWriter{CurrentDir: dir}
|
||||
if err := w.Write(r); err != nil {
|
||||
return fmt.Errorf("Failed to write summary report: %s", err)
|
||||
return xerrors.Errorf("Failed to write summary report: %w", err)
|
||||
}
|
||||
config.Conf.FormatJSON = before
|
||||
config.Conf.Diff = beforeDiff
|
||||
@@ -521,7 +545,7 @@ var jsonDirPattern = regexp.MustCompile(
|
||||
func ListValidJSONDirs() (dirs []string, err error) {
|
||||
var dirInfo []os.FileInfo
|
||||
if dirInfo, err = ioutil.ReadDir(config.Conf.ResultsDir); err != nil {
|
||||
err = fmt.Errorf("Failed to read %s: %s",
|
||||
err = xerrors.Errorf("Failed to read %s: %w",
|
||||
config.Conf.ResultsDir, err)
|
||||
return
|
||||
}
|
||||
@@ -559,20 +583,20 @@ func JSONDir(args []string) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Invalid path: %s", path)
|
||||
return "", xerrors.Errorf("Invalid path: %s", path)
|
||||
}
|
||||
|
||||
// PIPE
|
||||
if config.Conf.Pipe {
|
||||
bytes, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Failed to read stdin: %s", err)
|
||||
return "", xerrors.Errorf("Failed to read stdin: %w", err)
|
||||
}
|
||||
fields := strings.Fields(string(bytes))
|
||||
if 0 < len(fields) {
|
||||
return filepath.Join(config.Conf.ResultsDir, fields[0]), nil
|
||||
}
|
||||
return "", fmt.Errorf("Stdin is invalid: %s", string(bytes))
|
||||
return "", xerrors.Errorf("Stdin is invalid: %s", string(bytes))
|
||||
}
|
||||
|
||||
// returns latest dir when no args or no PIPE
|
||||
@@ -580,7 +604,7 @@ func JSONDir(args []string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
if len(dirs) == 0 {
|
||||
return "", fmt.Errorf("No results under %s",
|
||||
return "", xerrors.Errorf("No results under %s",
|
||||
config.Conf.ResultsDir)
|
||||
}
|
||||
return dirs[0], nil
|
||||
@@ -590,7 +614,7 @@ func JSONDir(args []string) (string, error) {
|
||||
func LoadScanResults(jsonDir string) (results models.ScanResults, err error) {
|
||||
var files []os.FileInfo
|
||||
if files, err = ioutil.ReadDir(jsonDir); err != nil {
|
||||
return nil, fmt.Errorf("Failed to read %s: %s", jsonDir, err)
|
||||
return nil, xerrors.Errorf("Failed to read %s: %w", jsonDir, err)
|
||||
}
|
||||
for _, f := range files {
|
||||
if filepath.Ext(f.Name()) != ".json" || strings.HasSuffix(f.Name(), "_diff.json") {
|
||||
@@ -605,7 +629,7 @@ func LoadScanResults(jsonDir string) (results models.ScanResults, err error) {
|
||||
results = append(results, *r)
|
||||
}
|
||||
if len(results) == 0 {
|
||||
return nil, fmt.Errorf("There is no json file under %s", jsonDir)
|
||||
return nil, xerrors.Errorf("There is no json file under %s", jsonDir)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -617,11 +641,11 @@ func loadOneServerScanResult(jsonFile string) (*models.ScanResult, error) {
|
||||
err error
|
||||
)
|
||||
if data, err = ioutil.ReadFile(jsonFile); err != nil {
|
||||
return nil, fmt.Errorf("Failed to read %s: %s", jsonFile, err)
|
||||
return nil, xerrors.Errorf("Failed to read %s: %w", jsonFile, err)
|
||||
}
|
||||
result := &models.ScanResult{}
|
||||
if err := json.Unmarshal(data, result); err != nil {
|
||||
return nil, fmt.Errorf("Failed to parse %s: %s", jsonFile, err)
|
||||
return nil, xerrors.Errorf("Failed to parse %s: %w", jsonFile, err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -192,13 +192,13 @@ func TestDiff(t *testing.T) {
|
||||
ScannedCves: models.VulnInfos{
|
||||
"CVE-2012-6702": {
|
||||
CveID: "CVE-2012-6702",
|
||||
AffectedPackages: models.PackageStatuses{{Name: "libexpat1"}},
|
||||
AffectedPackages: models.PackageFixStatuses{{Name: "libexpat1"}},
|
||||
DistroAdvisories: []models.DistroAdvisory{},
|
||||
CpeURIs: []string{},
|
||||
},
|
||||
"CVE-2014-9761": {
|
||||
CveID: "CVE-2014-9761",
|
||||
AffectedPackages: models.PackageStatuses{{Name: "libc-bin"}},
|
||||
AffectedPackages: models.PackageFixStatuses{{Name: "libc-bin"}},
|
||||
DistroAdvisories: []models.DistroAdvisory{},
|
||||
CpeURIs: []string{},
|
||||
},
|
||||
@@ -217,13 +217,13 @@ func TestDiff(t *testing.T) {
|
||||
ScannedCves: models.VulnInfos{
|
||||
"CVE-2012-6702": {
|
||||
CveID: "CVE-2012-6702",
|
||||
AffectedPackages: models.PackageStatuses{{Name: "libexpat1"}},
|
||||
AffectedPackages: models.PackageFixStatuses{{Name: "libexpat1"}},
|
||||
DistroAdvisories: []models.DistroAdvisory{},
|
||||
CpeURIs: []string{},
|
||||
},
|
||||
"CVE-2014-9761": {
|
||||
CveID: "CVE-2014-9761",
|
||||
AffectedPackages: models.PackageStatuses{{Name: "libc-bin"}},
|
||||
AffectedPackages: models.PackageFixStatuses{{Name: "libc-bin"}},
|
||||
DistroAdvisories: []models.DistroAdvisory{},
|
||||
CpeURIs: []string{},
|
||||
},
|
||||
@@ -254,7 +254,7 @@ func TestDiff(t *testing.T) {
|
||||
ScannedCves: models.VulnInfos{
|
||||
"CVE-2016-6662": {
|
||||
CveID: "CVE-2016-6662",
|
||||
AffectedPackages: models.PackageStatuses{{Name: "mysql-libs"}},
|
||||
AffectedPackages: models.PackageFixStatuses{{Name: "mysql-libs"}},
|
||||
DistroAdvisories: []models.DistroAdvisory{},
|
||||
CpeURIs: []string{},
|
||||
},
|
||||
@@ -292,7 +292,7 @@ func TestDiff(t *testing.T) {
|
||||
ScannedCves: models.VulnInfos{
|
||||
"CVE-2016-6662": {
|
||||
CveID: "CVE-2016-6662",
|
||||
AffectedPackages: models.PackageStatuses{{Name: "mysql-libs"}},
|
||||
AffectedPackages: models.PackageFixStatuses{{Name: "mysql-libs"}},
|
||||
DistroAdvisories: []models.DistroAdvisory{},
|
||||
CpeURIs: []string{},
|
||||
},
|
||||
@@ -348,7 +348,7 @@ func TestIsCveFixed(t *testing.T) {
|
||||
in: In{
|
||||
v: models.VulnInfo{
|
||||
CveID: "CVE-2016-6662",
|
||||
AffectedPackages: models.PackageStatuses{
|
||||
AffectedPackages: models.PackageFixStatuses{
|
||||
{
|
||||
Name: "mysql-libs",
|
||||
NotFixedYet: false,
|
||||
@@ -366,7 +366,7 @@ func TestIsCveFixed(t *testing.T) {
|
||||
ScannedCves: models.VulnInfos{
|
||||
"CVE-2016-6662": {
|
||||
CveID: "CVE-2016-6662",
|
||||
AffectedPackages: models.PackageStatuses{
|
||||
AffectedPackages: models.PackageFixStatuses{
|
||||
{
|
||||
Name: "mysql-libs",
|
||||
NotFixedYet: true,
|
||||
@@ -389,7 +389,7 @@ func TestIsCveFixed(t *testing.T) {
|
||||
in: In{
|
||||
v: models.VulnInfo{
|
||||
CveID: "CVE-2016-6662",
|
||||
AffectedPackages: models.PackageStatuses{
|
||||
AffectedPackages: models.PackageFixStatuses{
|
||||
{
|
||||
Name: "mysql-libs",
|
||||
NotFixedYet: true,
|
||||
@@ -407,7 +407,7 @@ func TestIsCveFixed(t *testing.T) {
|
||||
ScannedCves: models.VulnInfos{
|
||||
"CVE-2016-6662": {
|
||||
CveID: "CVE-2016-6662",
|
||||
AffectedPackages: models.PackageStatuses{
|
||||
AffectedPackages: models.PackageFixStatuses{
|
||||
{
|
||||
Name: "mysql-libs",
|
||||
NotFixedYet: true,
|
||||
|
||||
Reference in New Issue
Block a user