feat: init nightly vuls for blackhat

This commit is contained in:
MaineK00n
2022-11-15 11:26:26 +09:00
parent 1d97e91341
commit 3605645ff6
234 changed files with 6172 additions and 54872 deletions

179
pkg/detect/cpe/cpe.go Normal file
View File

@@ -0,0 +1,179 @@
package cpe
import (
"context"
"fmt"
"strings"
"github.com/hashicorp/go-version"
"github.com/knqyf263/go-cpe/common"
"github.com/knqyf263/go-cpe/matching"
"github.com/knqyf263/go-cpe/naming"
"github.com/pkg/errors"
"golang.org/x/exp/maps"
"github.com/future-architect/vuls/pkg/db"
dbTypes "github.com/future-architect/vuls/pkg/db/types"
"github.com/future-architect/vuls/pkg/types"
"github.com/future-architect/vuls/pkg/util"
)
type Detector struct{}
func (d Detector) Name() string {
return "cpe detector"
}
func (d Detector) Detect(ctx context.Context, host *types.Host) error {
if host.ScannedCves == nil {
host.ScannedCves = map[string]types.VulnInfo{}
}
vulndb, err := db.Open("boltdb", host.Config.Detect.Path, false)
if err != nil {
return errors.Wrapf(err, "open %s", host.Config.Detect.Path)
}
defer vulndb.Close()
for key, cpe := range host.Packages.CPE {
installed, err := naming.UnbindFS(cpe.CPE)
if err != nil {
return errors.Wrapf(err, "unbind %s", cpe.CPE)
}
var runningOn common.WellFormedName
if cpe.RunningOn != "" {
runningOn, err = naming.UnbindFS(cpe.RunningOn)
if err != nil {
return errors.Wrapf(err, "unbind %s", cpe.RunningOn)
}
}
cpes, err := vulndb.GetCPEConfiguration(fmt.Sprintf("%s:%s:%s", installed.GetString(common.AttributePart), installed.GetString(common.AttributeVendor), installed.GetString(common.AttributeProduct)))
if err != nil {
return errors.Wrap(err, "get cpe configuration")
}
for cveid, datasrcs := range cpes {
for datasrc, orcs := range datasrcs {
for id, andcs := range orcs {
for _, c := range andcs {
affected, err := compare(installed, &runningOn, c)
if err != nil {
return errors.Wrap(err, "compare")
}
if affected {
vinfo, ok := host.ScannedCves[cveid]
if !ok {
host.ScannedCves[cveid] = types.VulnInfo{ID: cveid}
}
vinfo.AffectedPackages = append(vinfo.AffectedPackages, types.AffectedPackage{
Name: key,
Source: fmt.Sprintf("%s:%s", datasrc, id),
})
vinfo.AffectedPackages = util.Unique(vinfo.AffectedPackages)
host.ScannedCves[cveid] = vinfo
break
}
}
}
}
}
}
vulns, err := vulndb.GetVulnerability(maps.Keys(host.ScannedCves))
if err != nil {
return errors.Wrap(err, "get vulnerability")
}
for cveid, datasrcs := range vulns {
vinfo := host.ScannedCves[cveid]
vinfo.Content = map[string]dbTypes.Vulnerability{}
for src, v := range datasrcs {
vinfo.Content[src] = v
}
host.ScannedCves[cveid] = vinfo
}
return nil
}
func compare(installedCPE common.WellFormedName, installedRunningOn *common.WellFormedName, target dbTypes.CPEConfiguration) (bool, error) {
var (
wfn common.WellFormedName
err error
)
if target.Vulnerable.CPEVersion == "2.3" {
wfn, err = naming.UnbindFS(target.Vulnerable.CPE)
} else {
wfn, err = naming.UnbindURI(target.Vulnerable.CPE)
}
if err != nil {
return false, errors.Wrapf(err, "unbind %s", target.Vulnerable.CPE)
}
if !matching.IsEqual(installedCPE, wfn) && !matching.IsSubset(installedCPE, wfn) {
return false, nil
}
for _, runningOn := range target.RunningOn {
if runningOn.CPEVersion == "2.3" {
wfn, err = naming.UnbindFS(runningOn.CPE)
} else {
wfn, err = naming.UnbindURI(runningOn.CPE)
}
if err != nil {
return false, errors.Wrapf(err, "unbind %s", runningOn.CPE)
}
if !matching.IsEqual(*installedRunningOn, wfn) && !matching.IsSubset(*installedRunningOn, wfn) {
return false, nil
}
}
if len(target.Vulnerable.Version) == 0 {
return true, nil
}
attrver := installedCPE.GetString(common.AttributeVersion)
switch attrver {
case "ANY":
return true, nil
case "NA":
return false, nil
default:
v, err := version.NewVersion(strings.ReplaceAll(attrver, "\\", ""))
if err != nil {
return false, errors.Wrapf(err, "parse version in %s", installedCPE.GetString(common.AttributeVersion))
}
for _, vconf := range target.Vulnerable.Version {
vconfv, err := version.NewVersion(vconf.Version)
if err != nil {
return false, errors.Wrapf(err, "parse version in %s", vconf.Version)
}
switch vconf.Operator {
case "eq":
if !v.Equal(vconfv) {
return false, nil
}
case "lt":
if !v.LessThan(vconfv) {
return false, nil
}
case "le":
if !v.LessThanOrEqual(vconfv) {
return false, nil
}
case "gt":
if !v.GreaterThan(vconfv) {
return false, nil
}
case "ge":
if !v.GreaterThanOrEqual(vconfv) {
return false, nil
}
default:
return false, errors.New("not supported operator")
}
}
return true, nil
}
}

151
pkg/detect/debian/debian.go Normal file
View File

@@ -0,0 +1,151 @@
package debian
import (
"context"
"fmt"
version "github.com/knqyf263/go-deb-version"
"github.com/pkg/errors"
"golang.org/x/exp/maps"
"github.com/future-architect/vuls/pkg/db"
dbTypes "github.com/future-architect/vuls/pkg/db/types"
"github.com/future-architect/vuls/pkg/types"
"github.com/future-architect/vuls/pkg/util"
)
type Detector struct{}
func (d Detector) Name() string {
return "debian detector"
}
func (d Detector) Detect(ctx context.Context, host *types.Host) error {
if host.ScannedCves == nil {
host.ScannedCves = map[string]types.VulnInfo{}
}
vulndb, err := db.Open("boltdb", host.Config.Detect.Path, false)
if err != nil {
return errors.Wrapf(err, "open %s", host.Config.Detect.Path)
}
defer vulndb.Close()
srcpkgs := map[string]string{}
for _, p := range host.Packages.OSPkg {
srcpkgs[p.SrcName] = p.SrcVersion
}
for srcname, srcver := range srcpkgs {
pkgs, err := vulndb.GetPackage(host.Family, host.Release, srcname)
if err != nil {
return errors.Wrap(err, "get package")
}
for cveid, datasrcs := range pkgs {
for datasrc, ps := range datasrcs {
for id, p := range ps {
switch p.Status {
case "fixed":
for _, andVs := range p.Version {
affected := true
for _, v := range andVs {
r, err := compare(v.Operator, srcver, v.Version)
if err != nil {
return errors.Wrap(err, "compare")
}
if !r {
affected = false
break
}
}
if affected {
vinfo, ok := host.ScannedCves[cveid]
if !ok {
host.ScannedCves[cveid] = types.VulnInfo{ID: cveid}
}
vinfo.AffectedPackages = append(vinfo.AffectedPackages, types.AffectedPackage{
Name: srcname,
Source: fmt.Sprintf("%s:%s", datasrc, id),
Status: p.Status,
})
vinfo.AffectedPackages = util.Unique(vinfo.AffectedPackages)
host.ScannedCves[cveid] = vinfo
}
}
case "open":
vinfo, ok := host.ScannedCves[cveid]
if !ok {
host.ScannedCves[cveid] = types.VulnInfo{ID: cveid}
}
vinfo.AffectedPackages = append(vinfo.AffectedPackages, types.AffectedPackage{
Name: srcname,
Source: fmt.Sprintf("%s:%s", datasrc, id),
Status: p.Status,
})
vinfo.AffectedPackages = util.Unique(vinfo.AffectedPackages)
host.ScannedCves[cveid] = vinfo
case "not affected":
}
}
}
}
}
vulns, err := vulndb.GetVulnerability(maps.Keys(host.ScannedCves))
if err != nil {
return errors.Wrap(err, "get vulnerability")
}
for cveid, datasrcs := range vulns {
vinfo := host.ScannedCves[cveid]
vinfo.Content = map[string]dbTypes.Vulnerability{}
for src, v := range datasrcs {
vinfo.Content[src] = v
}
host.ScannedCves[cveid] = vinfo
}
return nil
}
func compare(operator, srcver, ver string) (bool, error) {
v1, err := version.NewVersion(srcver)
if err != nil {
return false, errors.Wrap(err, "parse version")
}
v2, err := version.NewVersion(ver)
if err != nil {
return false, errors.Wrap(err, "parse version")
}
r := v1.Compare(v2)
switch operator {
case "eq":
if r == 0 {
return true, nil
}
return false, nil
case "lt":
if r < 0 {
return true, nil
}
return false, nil
case "le":
if r <= 0 {
return true, nil
}
return false, nil
case "gt":
if r > 0 {
return true, nil
}
return false, nil
case "ge":
if r >= 0 {
return true, nil
}
return false, nil
default:
return false, errors.New("not supported operator")
}
}

63
pkg/detect/detect.go Normal file
View File

@@ -0,0 +1,63 @@
package detect
import (
"context"
"time"
"github.com/pkg/errors"
"github.com/future-architect/vuls/pkg/cmd/version"
"github.com/future-architect/vuls/pkg/detect/cpe"
"github.com/future-architect/vuls/pkg/detect/debian"
detectTypes "github.com/future-architect/vuls/pkg/detect/types"
"github.com/future-architect/vuls/pkg/detect/ubuntu"
"github.com/future-architect/vuls/pkg/detect/windows"
"github.com/future-architect/vuls/pkg/types"
)
func Detect(ctx context.Context, host *types.Host) error {
if host.ScanError != "" {
return nil
}
var detectors []detectTypes.Detector
if len(host.Packages.OSPkg) > 0 {
switch host.Family {
case "debian":
detectors = append(detectors, debian.Detector{})
case "ubuntu":
detectors = append(detectors, ubuntu.Detector{})
default:
return errors.New("not implemented")
}
}
if len(host.Packages.KB) > 0 {
detectors = append(detectors, windows.Detector{})
}
if len(host.Packages.CPE) > 0 {
detectors = append(detectors, cpe.Detector{})
}
var err error
for {
if len(detectors) == 0 {
break
}
d := detectors[0]
if err = d.Detect(ctx, host); err != nil {
break
}
detectors = detectors[1:]
}
t := time.Now()
host.DetecteddAt = &t
host.DetectedVersion = version.Version
host.DetectedRevision = version.Revision
if err != nil {
return errors.Wrapf(err, "detect %s", host.Name)
}
return nil
}

12
pkg/detect/types/types.go Normal file
View File

@@ -0,0 +1,12 @@
package types
import (
"context"
"github.com/future-architect/vuls/pkg/types"
)
type Detector interface {
Name() string
Detect(context.Context, *types.Host) error
}

151
pkg/detect/ubuntu/ubuntu.go Normal file
View File

@@ -0,0 +1,151 @@
package ubuntu
import (
"context"
"fmt"
version "github.com/knqyf263/go-deb-version"
"github.com/pkg/errors"
"golang.org/x/exp/maps"
"github.com/future-architect/vuls/pkg/db"
dbTypes "github.com/future-architect/vuls/pkg/db/types"
"github.com/future-architect/vuls/pkg/types"
"github.com/future-architect/vuls/pkg/util"
)
type Detector struct{}
func (d Detector) Name() string {
return "ubuntu detector"
}
func (d Detector) Detect(ctx context.Context, host *types.Host) error {
if host.ScannedCves == nil {
host.ScannedCves = map[string]types.VulnInfo{}
}
vulndb, err := db.Open("boltdb", host.Config.Detect.Path, false)
if err != nil {
return errors.Wrapf(err, "open %s", host.Config.Detect.Path)
}
defer vulndb.Close()
srcpkgs := map[string]string{}
for _, p := range host.Packages.OSPkg {
srcpkgs[p.SrcName] = p.SrcVersion
}
for srcname, srcver := range srcpkgs {
pkgs, err := vulndb.GetPackage(host.Family, host.Release, srcname)
if err != nil {
return errors.Wrap(err, "get package")
}
for cveid, datasrcs := range pkgs {
for datasrc, ps := range datasrcs {
for id, p := range ps {
switch p.Status {
case "released":
for _, andVs := range p.Version {
affected := true
for _, v := range andVs {
r, err := compare(v.Operator, srcver, v.Version)
if err != nil {
return errors.Wrap(err, "compare")
}
if !r {
affected = false
break
}
}
if affected {
vinfo, ok := host.ScannedCves[cveid]
if !ok {
host.ScannedCves[cveid] = types.VulnInfo{ID: cveid}
}
vinfo.AffectedPackages = append(vinfo.AffectedPackages, types.AffectedPackage{
Name: srcname,
Source: fmt.Sprintf("%s:%s", datasrc, id),
Status: p.Status,
})
vinfo.AffectedPackages = util.Unique(vinfo.AffectedPackages)
host.ScannedCves[cveid] = vinfo
}
}
case "needed", "deferred", "pending":
vinfo, ok := host.ScannedCves[cveid]
if !ok {
host.ScannedCves[cveid] = types.VulnInfo{ID: cveid}
}
vinfo.AffectedPackages = append(vinfo.AffectedPackages, types.AffectedPackage{
Name: srcname,
Source: fmt.Sprintf("%s:%s", datasrc, id),
Status: p.Status,
})
vinfo.AffectedPackages = util.Unique(vinfo.AffectedPackages)
host.ScannedCves[cveid] = vinfo
case "not-affected", "DNE":
}
}
}
}
}
vulns, err := vulndb.GetVulnerability(maps.Keys(host.ScannedCves))
if err != nil {
return errors.Wrap(err, "get vulnerability")
}
for cveid, datasrcs := range vulns {
vinfo := host.ScannedCves[cveid]
vinfo.Content = map[string]dbTypes.Vulnerability{}
for src, v := range datasrcs {
vinfo.Content[src] = v
}
host.ScannedCves[cveid] = vinfo
}
return nil
}
func compare(operator, srcver, ver string) (bool, error) {
v1, err := version.NewVersion(srcver)
if err != nil {
return false, errors.Wrap(err, "parse version")
}
v2, err := version.NewVersion(ver)
if err != nil {
return false, errors.Wrap(err, "parse version")
}
r := v1.Compare(v2)
switch operator {
case "eq":
if r == 0 {
return true, nil
}
return false, nil
case "lt":
if r < 0 {
return true, nil
}
return false, nil
case "le":
if r <= 0 {
return true, nil
}
return false, nil
case "gt":
if r > 0 {
return true, nil
}
return false, nil
case "ge":
if r >= 0 {
return true, nil
}
return false, nil
default:
return false, errors.New("not supported operator")
}
}

View File

@@ -0,0 +1,120 @@
package windows
import (
"context"
"fmt"
"github.com/pkg/errors"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
"github.com/future-architect/vuls/pkg/db"
dbTypes "github.com/future-architect/vuls/pkg/db/types"
"github.com/future-architect/vuls/pkg/types"
"github.com/future-architect/vuls/pkg/util"
)
type Detector struct{}
func (d Detector) Name() string {
return "windows detector"
}
func (d Detector) Detect(ctx context.Context, host *types.Host) error {
if host.ScannedCves == nil {
host.ScannedCves = map[string]types.VulnInfo{}
}
vulndb, err := db.Open("boltdb", host.Config.Detect.Path, false)
if err != nil {
return errors.Wrapf(err, "open %s", host.Config.Detect.Path)
}
defer vulndb.Close()
supercedences, err := vulndb.GetSupercedence(host.Packages.KB)
if err != nil {
return errors.Wrap(err, "get supercedence")
}
var unapplied []string
for _, kbs := range supercedences {
var applied bool
for _, kb := range kbs {
if slices.Contains(host.Packages.KB, kb) {
applied = true
break
}
}
if !applied {
unapplied = append(unapplied, kbs...)
}
}
unapplied = util.Unique(unapplied)
products, err := vulndb.GetKBtoProduct(host.Release, append(host.Packages.KB, unapplied...))
if err != nil {
return errors.Wrap(err, "get product from kb")
}
if !slices.Contains(products, host.Release) {
products = append(products, host.Release)
}
for _, product := range util.Unique(products) {
pkgs, err := vulndb.GetPackage(host.Family, host.Release, product)
if err != nil {
return errors.Wrap(err, "get package")
}
for cveid, datasrcs := range pkgs {
for datasrc, ps := range datasrcs {
for id, p := range ps {
switch p.Status {
case "fixed":
for _, v := range p.Version {
if slices.Contains(unapplied, v[0].Version) {
vinfo, ok := host.ScannedCves[cveid]
if !ok {
host.ScannedCves[cveid] = types.VulnInfo{ID: cveid}
}
vinfo.AffectedPackages = append(vinfo.AffectedPackages, types.AffectedPackage{
Name: fmt.Sprintf("%s: KB%s", product, v[0].Version),
Source: fmt.Sprintf("%s:%s", datasrc, id),
Status: p.Status,
})
vinfo.AffectedPackages = util.Unique(vinfo.AffectedPackages)
host.ScannedCves[cveid] = vinfo
}
}
case "unfixed":
vinfo, ok := host.ScannedCves[cveid]
if !ok {
host.ScannedCves[cveid] = types.VulnInfo{ID: cveid}
}
vinfo.AffectedPackages = append(vinfo.AffectedPackages, types.AffectedPackage{
Name: product,
Source: fmt.Sprintf("%s:%s", datasrc, id),
Status: p.Status,
})
vinfo.AffectedPackages = util.Unique(vinfo.AffectedPackages)
host.ScannedCves[cveid] = vinfo
}
}
}
}
}
vulns, err := vulndb.GetVulnerability(maps.Keys(host.ScannedCves))
if err != nil {
return errors.Wrap(err, "get vulnerability")
}
for cveid, datasrcs := range vulns {
vinfo := host.ScannedCves[cveid]
vinfo.Content = map[string]dbTypes.Vulnerability{}
for src, v := range datasrcs {
vinfo.Content[src] = v
}
host.ScannedCves[cveid] = vinfo
}
return nil
}