feat(scan): WordPress Vulnerability Scan (core, plugin, theme) (#769)

https://github.com/future-architect/vuls/pull/769
This commit is contained in:
kazuminn
2019-04-08 17:27:44 +09:00
committed by Kota Kanbe
parent 91df593566
commit 99c65eff48
59 changed files with 1284 additions and 602 deletions

View File

@@ -30,6 +30,7 @@ import (
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
version "github.com/knqyf263/go-deb-version"
"golang.org/x/xerrors"
)
// inherit OsTypeInterface
@@ -62,7 +63,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. 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)
return false, deb, xerrors.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
@@ -160,7 +161,7 @@ func (o *debian) checkIfSudoNoPasswd() error {
r := o.exec(cmd, sudo)
if !r.isSuccess() {
o.log.Errorf("sudo error on %s", r)
return fmt.Errorf("Failed to sudo: %s", r)
return xerrors.Errorf("Failed to sudo: %s", r)
}
}
@@ -171,7 +172,7 @@ func (o *debian) checkIfSudoNoPasswd() error {
r := o.exec(cmd, sudo)
if !r.isSuccess() {
o.log.Errorf("sudo error on %s", r)
return fmt.Errorf("Failed to sudo: %s", r)
return xerrors.Errorf("Failed to sudo: %s", r)
}
}
@@ -230,7 +231,7 @@ func (o *debian) checkDeps() error {
}
dep.logFunc(msg)
if dep.required {
return fmt.Errorf(msg)
return xerrors.New(msg)
}
continue
}
@@ -242,7 +243,7 @@ func (o *debian) checkDeps() error {
}
dep.logFunc(msg)
if dep.required {
return fmt.Errorf(msg)
return xerrors.New(msg)
}
}
@@ -323,7 +324,7 @@ func (o *debian) rebootRequired() (bool, error) {
case 1:
return false, nil
default:
return false, fmt.Errorf("Failed to check reboot reauired: %s", r)
return false, xerrors.Errorf("Failed to check reboot reauired: %s", r)
}
}
@@ -333,7 +334,7 @@ func (o *debian) scanInstalledPackages() (models.Packages, models.Packages, mode
updatable := models.Packages{}
r := o.exec(dpkgQuery, noSudo)
if !r.isSuccess() {
return nil, nil, nil, fmt.Errorf("Failed to SSH: %s", r)
return nil, nil, nil, xerrors.Errorf("Failed to SSH: %s", r)
}
installed, srcPacks, err := o.parseInstalledPackages(r.Stdout)
@@ -364,7 +365,7 @@ func (o *debian) scanInstalledPackages() (models.Packages, models.Packages, mode
// Fill the candidate versions of upgradable packages
err = o.fillCandidateVersion(updatable)
if err != nil {
return nil, nil, nil, fmt.Errorf("Failed to fill candidate versions. err: %s", err)
return nil, nil, nil, xerrors.Errorf("Failed to fill candidate versions. err: %s", err)
}
installed.MergeNewVersion(updatable)
@@ -383,7 +384,7 @@ func (o *debian) parseInstalledPackages(stdout string) (models.Packages, models.
if trimmed := strings.TrimSpace(line); len(trimmed) != 0 {
name, status, version, srcName, srcVersion, err := o.parseScannedPackagesLine(trimmed)
if err != nil || len(status) < 2 {
return nil, nil, fmt.Errorf(
return nil, nil, xerrors.Errorf(
"Debian: Failed to parse package line: %s", line)
}
@@ -448,14 +449,14 @@ func (o *debian) parseScannedPackagesLine(line string) (name, status, version, s
return
}
return "", "", "", "", "", fmt.Errorf("Unknown format: %s", line)
return "", "", "", "", "", xerrors.Errorf("Unknown format: %s", line)
}
func (o *debian) aptGetUpdate() error {
o.log.Infof("apt-get update...")
cmd := util.PrependProxyEnv("apt-get update")
if r := o.exec(cmd, sudo); !r.isSuccess() {
return fmt.Errorf("Failed to apt-get update: %s", r)
return xerrors.Errorf("Failed to apt-get update: %s", r)
}
return nil
}
@@ -477,7 +478,7 @@ func (o *debian) scanUnsecurePackages(updatable models.Packages) (models.VulnInf
// Collect CVE information of upgradable packages
vulnInfos, err := o.scanChangelogs(updatable, meta)
if err != nil {
return nil, fmt.Errorf("Failed to scan unsecure packages. err: %s", err)
return nil, xerrors.Errorf("Failed to scan unsecure packages. err: %s", err)
}
return vulnInfos, nil
@@ -487,7 +488,7 @@ func (o *debian) ensureChangelogCache(current cache.Meta) (*cache.Meta, error) {
// Search from cache
cached, found, err := cache.DB.GetMeta(current.Name)
if err != nil {
return nil, fmt.Errorf(
return nil, xerrors.Errorf(
"Failed to get meta. Please remove cache.db and then try again. err: %s", err)
}
@@ -495,7 +496,7 @@ func (o *debian) ensureChangelogCache(current cache.Meta) (*cache.Meta, error) {
o.log.Debugf("Not found in meta: %s", current.Name)
err = cache.DB.EnsureBuckets(current)
if err != nil {
return nil, fmt.Errorf("Failed to ensure buckets. err: %s", err)
return nil, xerrors.Errorf("Failed to ensure buckets. err: %s", err)
}
return &current, nil
}
@@ -505,7 +506,7 @@ func (o *debian) ensureChangelogCache(current cache.Meta) (*cache.Meta, error) {
o.log.Debugf("Need to refesh meta: %s", current.Name)
err = cache.DB.EnsureBuckets(current)
if err != nil {
return nil, fmt.Errorf("Failed to ensure buckets. err: %s", err)
return nil, xerrors.Errorf("Failed to ensure buckets. err: %s", err)
}
return &current, nil
@@ -526,17 +527,17 @@ func (o *debian) fillCandidateVersion(updatables models.Packages) (err error) {
cmd := fmt.Sprintf("LANGUAGE=en_US.UTF-8 apt-cache policy %s", strings.Join(names, " "))
r := o.exec(cmd, noSudo)
if !r.isSuccess() {
return fmt.Errorf("Failed to SSH: %s", r)
return xerrors.Errorf("Failed to SSH: %s", r)
}
packAptPolicy := o.splitAptCachePolicy(r.Stdout)
for k, v := range packAptPolicy {
ver, err := o.parseAptCachePolicy(v, k)
if err != nil {
return fmt.Errorf("Failed to parse %s", err)
return xerrors.Errorf("Failed to parse %w", err)
}
pack, ok := updatables[k]
if !ok {
return fmt.Errorf("Not found: %s", k)
return xerrors.Errorf("Not found: %s", k)
}
pack.NewVersion = ver.Candidate
pack.Repository = ver.Repo
@@ -551,7 +552,7 @@ func (o *debian) getUpdatablePackNames() (packNames []string, err error) {
if r.isSuccess(0, 1) {
return o.parseAptGetUpgrade(r.Stdout)
}
return packNames, fmt.Errorf(
return packNames, xerrors.Errorf(
"Failed to %s. status: %d, stdout: %s, stderr: %s",
cmd, r.ExitStatus, r.Stdout, r.Stderr)
}
@@ -573,11 +574,11 @@ func (o *debian) parseAptGetUpgrade(stdout string) (updatableNames []string, err
if len(result) == 2 {
nUpdatable, err := strconv.Atoi(result[1])
if err != nil {
return nil, fmt.Errorf(
return nil, xerrors.Errorf(
"Failed to scan upgradable packages number. line: %s", line)
}
if nUpdatable != len(updatableNames) {
return nil, fmt.Errorf(
return nil, xerrors.Errorf(
"Failed to scan upgradable packages, expected: %s, detected: %d",
result[1], len(updatableNames))
}
@@ -593,7 +594,7 @@ func (o *debian) parseAptGetUpgrade(stdout string) (updatableNames []string, err
}
if !stopLineFound {
// There are upgrades, but not found the stop line.
return nil, fmt.Errorf("Failed to scan upgradable packages")
return nil, xerrors.New("Failed to scan upgradable packages")
}
return
}
@@ -677,11 +678,11 @@ func (o *debian) scanChangelogs(updatablePacks models.Packages, meta *cache.Meta
case err := <-errChan:
errs = append(errs, err)
case <-timeout:
errs = append(errs, fmt.Errorf("Timeout scanPackageCveIDs"))
errs = append(errs, xerrors.New("Timeout scanPackageCveIDs"))
}
}
if 0 < len(errs) {
return nil, fmt.Errorf("%v", errs)
return nil, xerrors.Errorf("errs: %w", errs)
}
var cveIDs []DetectedCveID
@@ -691,9 +692,9 @@ func (o *debian) scanChangelogs(updatablePacks models.Packages, meta *cache.Meta
o.log.Debugf("%d Cves are found. cves: %v", len(cveIDs), cveIDs)
vinfos := models.VulnInfos{}
for cveID, names := range cvePackages {
affected := models.PackageStatuses{}
affected := models.PackageFixStatuses{}
for _, n := range names {
affected = append(affected, models.PackageStatus{Name: n})
affected = append(affected, models.PackageFixStatus{Name: n})
}
vinfos[cveID.CveID] = models.VulnInfo{
@@ -764,7 +765,7 @@ func (o *debian) fetchParseChangelog(pack models.Package) ([]DetectedCveID, *mod
err := cache.DB.PutChangelog(
o.getServerInfo().GetServerName(), pack.Name, pack.Changelog.Contents)
if err != nil {
return nil, nil, fmt.Errorf("Failed to put changelog into cache")
return nil, nil, xerrors.New("Failed to put changelog into cache")
}
}
@@ -838,7 +839,7 @@ var cveRe = regexp.MustCompile(`(CVE-\d{4}-\d{4,})`)
func (o *debian) parseChangelog(changelog, name, ver string, confidence models.Confidence) ([]DetectedCveID, *models.Package, error) {
installedVer, err := version.NewVersion(ver)
if err != nil {
return nil, nil, fmt.Errorf("Failed to parse installed version: %s, %s", ver, err)
return nil, nil, xerrors.Errorf("Failed to parse installed version: %s, err: %w", ver, err)
}
buf, cveIDs := []string{}, []string{}
scanner := bufio.NewScanner(strings.NewReader(changelog))
@@ -876,7 +877,7 @@ func (o *debian) parseChangelog(changelog, name, ver string, confidence models.C
Contents: "",
Method: models.FailedToFindVersionInChangelog,
}
return nil, &pack, fmt.Errorf(
return nil, &pack, xerrors.Errorf(
"Failed to scan CVE IDs. The version is not in changelog. name: %s, version: %s",
name, ver)
}
@@ -958,7 +959,7 @@ func (o *debian) parseAptCachePolicy(stdout, name string) (packCandidateVer, err
}
nextline:
}
return ver, fmt.Errorf("Unknown Format: %s", stdout)
return ver, xerrors.Errorf("Unknown Format: %s", stdout)
}
func (o *debian) checkrestart() error {
@@ -971,7 +972,7 @@ func (o *debian) checkrestart() error {
cmd := "LANGUAGE=en_US.UTF-8 checkrestart"
r := o.exec(cmd, sudo)
if !r.isSuccess() {
return fmt.Errorf(
return xerrors.Errorf(
"Failed to %s. status: %d, stdout: %s, stderr: %s",
cmd, r.ExitStatus, r.Stdout, r.Stderr)
}