diff --git a/detector/detector.go b/detector/detector.go index 239a1a03a0..e338507596 100644 --- a/detector/detector.go +++ b/detector/detector.go @@ -317,14 +317,11 @@ func DetectPkgCves(r *models.ScanResult, gostCnf config.GostConf, vuls2Conf conf switch r.Family { case constant.RedHat, constant.CentOS, constant.Fedora, constant.Alma, constant.Rocky, constant.Oracle, constant.Amazon, constant.OpenSUSE, constant.OpenSUSELeap, constant.SUSEEnterpriseServer, constant.SUSEEnterpriseDesktop, - constant.Debian, constant.Raspbian, constant.Ubuntu, constant.Alpine: + constant.Debian, constant.Raspbian, constant.Ubuntu, constant.Alpine, + constant.Windows: if err := vuls2.Detect(r, vuls2Conf, noProgress); err != nil { return xerrors.Errorf("Failed to detect CVE with Vuls2: %w", err) } - case constant.Windows: - if err := detectPkgsCvesWithGost(gostCnf, r, logOpts); err != nil { - return xerrors.Errorf("Failed to detect CVE with gost: %w", err) - } default: return xerrors.Errorf("Unsupported detection methods for %s", r.Family) } @@ -496,27 +493,6 @@ func fillCertAlerts(cvedetail *cvemodels.CveDetail) (dict models.AlertDict) { return dict } -func detectPkgsCvesWithGost(cnf config.GostConf, r *models.ScanResult, logOpts logging.LogOpts) error { - client, err := gost.NewGostClient(cnf, r.Family, logOpts) - if err != nil { - return xerrors.Errorf("Failed to new a gost client: %w", err) - } - defer func() { - if err := client.CloseDB(); err != nil { - logging.Log.Errorf("Failed to close the gost DB. err: %+v", err) - } - }() - - nCVEs, err := client.DetectCVEs(r, true) - if err != nil { - return xerrors.Errorf("Failed to detect CVEs with gost: %w", err) - } - - logging.Log.Infof("%s: %d CVEs are detected with gost", r.FormatServerName(), nCVEs) - - return nil -} - // DetectCpeURIsCves detects CVEs of given CPE-URIs func DetectCpeURIsCves(r *models.ScanResult, cpes []Cpe, cnf config.GoCveDictConf, logOpts logging.LogOpts) error { client, err := newGoCveDictClient(&cnf, logOpts) diff --git a/detector/vuls2/vendor.go b/detector/vuls2/vendor.go index 00a29101ac..c1048d39f4 100644 --- a/detector/vuls2/vendor.go +++ b/detector/vuls2/vendor.go @@ -47,6 +47,8 @@ func preConvertBinaryVersion(family, version string) string { func toVuls2Family(vuls0Family, vuls0Release string) string { switch vuls0Family { + case constant.Windows: + return ecosystemTypes.EcosystemTypeMicrosoft case constant.Raspbian: return ecosystemTypes.EcosystemTypeDebian case constant.SUSEEnterpriseServer, constant.SUSEEnterpriseDesktop: @@ -577,6 +579,12 @@ func advisoryReference(e ecosystemTypes.Ecosystem, s sourceTypes.SourceID, da mo Source: "SUSE", RefID: da.AdvisoryID, }, nil + case ecosystemTypes.EcosystemTypeMicrosoft: + return models.Reference{ + Link: fmt.Sprintf("https://msrc.microsoft.com/update-guide/vulnerability/%s", da.AdvisoryID), + Source: "MICROSOFT", + RefID: da.AdvisoryID, + }, nil default: return models.Reference{}, xerrors.Errorf("unsupported family: %s", et) } @@ -600,6 +608,8 @@ func cveContentSourceLink(ccType models.CveContentType, v vulnerabilityTypes.Vul return fmt.Sprintf("https://security.alpinelinux.org/vuln/%s", v.Content.ID) case models.Nvd: return fmt.Sprintf("https://nvd.nist.gov/vuln/detail/%s", v.Content.ID) + case models.Microsoft: + return fmt.Sprintf("https://msrc.microsoft.com/update-guide/vulnerability/%s", v.Content.ID) default: return "" } @@ -731,6 +741,22 @@ func compareSourceID(e ecosystemTypes.Ecosystem, a, b sourceTypes.SourceID) int } } return cmp.Compare(preferenceFn(a), preferenceFn(b)) + case ecosystemTypes.EcosystemTypeMicrosoft: + preferenceFn := func(sourceID sourceTypes.SourceID) int { + switch sourceID { + case sourceTypes.MicrosoftCVRF: + return 5 + case sourceTypes.MicrosoftCSAF: + return 4 + case sourceTypes.MicrosoftBulletin: + return 3 + case sourceTypes.MicrosoftWSUSSCN2, sourceTypes.MicrosoftMSUC: + return 2 + default: + return 1 + } + } + return cmp.Compare(preferenceFn(a), preferenceFn(b)) default: return 0 } @@ -828,6 +854,8 @@ func toCveContentType(e ecosystemTypes.Ecosystem, s sourceTypes.SourceID) models } case ecosystemTypes.EcosystemTypeSUSELinuxEnterprise, ecosystemTypes.EcosystemTypeOpenSUSE, ecosystemTypes.EcosystemTypeOpenSUSELeap, ecosystemTypes.EcosystemTypeOpenSUSETumbleweed: return models.SUSE + case ecosystemTypes.EcosystemTypeMicrosoft: + return models.Microsoft default: return models.NewCveContentType(et) } @@ -978,6 +1006,8 @@ func toVuls0Confidence(e ecosystemTypes.Ecosystem, s sourceTypes.SourceID) model default: return models.OvalMatch } + case ecosystemTypes.EcosystemTypeMicrosoft: + return models.WindowsUpdateSearch default: return models.Confidence{ Score: 0, diff --git a/detector/vuls2/vuls2.go b/detector/vuls2/vuls2.go index 197d60093e..e8672def18 100644 --- a/detector/vuls2/vuls2.go +++ b/detector/vuls2/vuls2.go @@ -156,7 +156,27 @@ func preConvert(sr *models.ScanResult) scanTypes.ScanResult { Version: sr.RunningKernel.Version, RebootRequired: sr.RunningKernel.RebootRequired, }, - OSPackages: slices.Collect(maps.Values(pkgs)), + OSPackages: func() []scanTypes.OSPackage { + ps := slices.Collect(maps.Values(pkgs)) + // For Windows, include the OS release as a synthetic package so that + // kernel-version-based detection can report the correct release name. + if sr.Family == constant.Windows && sr.RunningKernel.Version != "" { + ps = append(ps, scanTypes.OSPackage{ + Name: toVuls2Release(sr.Family, sr.Release), + Version: sr.RunningKernel.Version, + }) + } + return ps + }(), + MicrosoftKB: func() scanTypes.MicrosoftKB { + if sr.WindowsKB == nil { + return scanTypes.MicrosoftKB{} + } + return scanTypes.MicrosoftKB{ + Applied: sr.WindowsKB.Applied, + Unapplied: sr.WindowsKB.Unapplied, + } + }(), ScannedAt: time.Now(), ScannedBy: version.String(), @@ -166,34 +186,32 @@ func preConvert(sr *models.ScanResult) scanTypes.ScanResult { func detect(sesh *session.Session, sr scanTypes.ScanResult) (detectTypes.DetectResult, error) { detected := make(map[dataTypes.RootID]detectTypes.VulnerabilityData) - if len(sr.OSPackages) > 0 { - m, err := ospkg.Detect(sesh.Storage(), sr, runtime.NumCPU()) - if err != nil { - return detectTypes.DetectResult{}, xerrors.Errorf("Failed to detect os packages. err: %w", err) + m, err := ospkg.Detect(sesh.Storage(), sr, runtime.NumCPU()) + if err != nil { + return detectTypes.DetectResult{}, xerrors.Errorf("Failed to detect os packages. err: %w", err) + } + for rootID, d := range m { + base := detectTypes.VulnerabilityData{ + ID: rootID, + Detections: []detectTypes.VulnerabilityDataDetection{d}, } - for rootID, d := range m { - base := detectTypes.VulnerabilityData{ - ID: rootID, - Detections: []detectTypes.VulnerabilityDataDetection{d}, - } - avs, err := sesh.GetVulnerabilityData(rootID, dbTypes.Filter{ - Contents: []dbTypes.FilterContentType{ - dbTypes.FilterContentTypeAdvisories, - dbTypes.FilterContentTypeVulnerabilities, - }, - RootIDs: []dataTypes.RootID{rootID}, - Ecosystems: []ecosystemTypes.Ecosystem{d.Ecosystem}, - DataSources: slices.Collect(maps.Keys(d.Contents)), - }) - if err != nil { - return detectTypes.DetectResult{}, xerrors.Errorf("Failed to get vulnerability data. RootID: %s, err: %w", rootID, err) - } - - base.Advisories = avs.Advisories - base.Vulnerabilities = avs.Vulnerabilities - detected[rootID] = base + avs, err := sesh.GetVulnerabilityData(rootID, dbTypes.Filter{ + Contents: []dbTypes.FilterContentType{ + dbTypes.FilterContentTypeAdvisories, + dbTypes.FilterContentTypeVulnerabilities, + }, + RootIDs: []dataTypes.RootID{rootID}, + Ecosystems: []ecosystemTypes.Ecosystem{d.Ecosystem}, + DataSources: slices.Collect(maps.Keys(d.Contents)), + }) + if err != nil { + return detectTypes.DetectResult{}, xerrors.Errorf("Failed to get vulnerability data. RootID: %s, err: %w", rootID, err) } + + base.Advisories = avs.Advisories + base.Vulnerabilities = avs.Vulnerabilities + detected[rootID] = base } var sourceIDs []sourceTypes.SourceID @@ -420,6 +438,19 @@ func postConvert(scanned scanTypes.ScanResult, detected detectTypes.DetectResult vi.AffectedPackages = ps vi.CpeURIs = am[vi.CveID].cpes + // Populate WindowsKBFixedIns and KB-based DistroAdvisories for Microsoft detections + if string(scanned.Family) == ecosystemTypes.EcosystemTypeMicrosoft { + for _, p := range ps { + if kbID, ok := strings.CutPrefix(p.FixedIn, "KB"); ok { + if !slices.Contains(vi.WindowsKBFixedIns, kbID) { + vi.WindowsKBFixedIns = append(vi.WindowsKBFixedIns, kbID) + } + da := models.DistroAdvisory{AdvisoryID: p.FixedIn, Description: "Microsoft Knowledge Base"} + vi.DistroAdvisories.AppendIfMissing(&da) + } + } + } + vim[vi.CveID] = vi } @@ -552,59 +583,76 @@ func walkCriteria(e ecosystemTypes.Ecosystem, sourceID sourceTypes.SourceID, ca return nil, nil, true, nil } - if cn.Criterion.Type != criterionTypes.CriterionTypeVersion || cn.Criterion.Version == nil { - continue - } - - if ignoreCriterion(e, cn, tag) { - continue - } - - fcn, err := filterCriterion(e, scanned, cn) - if err != nil { - return nil, nil, false, xerrors.Errorf("Failed to filter criterion. err: %w", err) - } + switch cn.Criterion.Type { + case criterionTypes.CriterionTypeVersion: + if cn.Criterion.Version == nil { + continue + } - switch fcn.Criterion.Version.Package.Type { - case vcPackageTypes.PackageTypeBinary, vcPackageTypes.PackageTypeSource: - if !fcn.Criterion.Version.Vulnerable { + if ignoreCriterion(e, cn, tag) { continue } - rangeType, fixedIn := func() (vcAffectedRangeTypes.RangeType, string) { - if fcn.Criterion.Version.Affected == nil { - return vcAffectedRangeTypes.RangeTypeUnknown, "" + fcn, err := filterCriterion(e, scanned, cn) + if err != nil { + return nil, nil, false, xerrors.Errorf("Failed to filter criterion. err: %w", err) + } + + switch fcn.Criterion.Version.Package.Type { + case vcPackageTypes.PackageTypeBinary, vcPackageTypes.PackageTypeSource: + if !fcn.Criterion.Version.Vulnerable { + continue } - return fcn.Criterion.Version.Affected.Type, selectFixedIn(fcn.Criterion.Version.Affected.Type, fcn.Criterion.Version.Affected.Fixed) - }() - for _, index := range fcn.Accepts.Version { - if len(scanned.OSPackages) <= index { - return nil, nil, false, xerrors.Errorf("Too large OSPackage index. len(OSPackage): %d, index: %d", len(scanned.OSPackages), index) + rangeType, fixedIn := func() (vcAffectedRangeTypes.RangeType, string) { + if fcn.Criterion.Version.Affected == nil { + return vcAffectedRangeTypes.RangeTypeUnknown, "" + } + return fcn.Criterion.Version.Affected.Type, selectFixedIn(fcn.Criterion.Version.Affected.Type, fcn.Criterion.Version.Affected.Fixed) + }() + + for _, index := range fcn.Accepts.Version { + if len(scanned.OSPackages) <= index { + return nil, nil, false, xerrors.Errorf("Too large OSPackage index. len(OSPackage): %d, index: %d", len(scanned.OSPackages), index) + } + statuses = append(statuses, packStatus{ + rangeType: rangeType, + status: models.PackageFixStatus{ + Name: affectedPackageName(e, scanned.OSPackages[index]), + FixState: func() string { + if fcn.Criterion.Version.FixStatus == nil { + return "" + } + return fixState(e, sourceID, fcn.Criterion.Version.FixStatus.Vendor) + }(), + FixedIn: fixedIn, + NotFixedYet: fcn.Criterion.Version.FixStatus == nil || fcn.Criterion.Version.FixStatus.Class != vcFixStatusTypes.ClassFixed, + }, + }) } - statuses = append(statuses, packStatus{ - rangeType: rangeType, - status: models.PackageFixStatus{ - Name: affectedPackageName(e, scanned.OSPackages[index]), - FixState: func() string { - if fcn.Criterion.Version.FixStatus == nil { - return "" - } - return fixState(e, sourceID, fcn.Criterion.Version.FixStatus.Vendor) - }(), - FixedIn: fixedIn, - NotFixedYet: fcn.Criterion.Version.FixStatus == nil || fcn.Criterion.Version.FixStatus.Class != vcFixStatusTypes.ClassFixed, - }, - }) - } - case vcPackageTypes.PackageTypeCPE: - for _, index := range fcn.Accepts.Version { - if len(scanned.CPE) <= index { - return nil, nil, false, xerrors.Errorf("Too large CPE index. len(CPE): %d, index: %d", len(scanned.CPE), index) + case vcPackageTypes.PackageTypeCPE: + for _, index := range fcn.Accepts.Version { + if len(scanned.CPE) <= index { + return nil, nil, false, xerrors.Errorf("Too large CPE index. len(CPE): %d, index: %d", len(scanned.CPE), index) + } } + cpes = append(cpes, string(*fcn.Criterion.Version.Package.CPE)) + default: + } + case criterionTypes.CriterionTypeKB: + if cn.Criterion.KB == nil || !cn.Accepts.KB { + continue } - cpes = append(cpes, string(*fcn.Criterion.Version.Package.CPE)) + statuses = append(statuses, packStatus{ + rangeType: vcAffectedRangeTypes.RangeTypeUnknown, + status: models.PackageFixStatus{ + Name: cn.Criterion.KB.Product, + FixedIn: fmt.Sprintf("KB%s", cn.Criterion.KB.KBID), + NotFixedYet: true, + }, + }) default: + continue } } return statuses, cpes, false, nil diff --git a/detector/vuls2/vuls2_test.go b/detector/vuls2/vuls2_test.go index 79e0aad425..0411ab65cf 100644 --- a/detector/vuls2/vuls2_test.go +++ b/detector/vuls2/vuls2_test.go @@ -13,6 +13,7 @@ import ( conditionTypes "github.com/MaineK00n/vuls-data-update/pkg/extract/types/data/detection/condition" criteriaTypes "github.com/MaineK00n/vuls-data-update/pkg/extract/types/data/detection/condition/criteria" criterionTypes "github.com/MaineK00n/vuls-data-update/pkg/extract/types/data/detection/condition/criteria/criterion" + kbcriterionTypes "github.com/MaineK00n/vuls-data-update/pkg/extract/types/data/detection/condition/criteria/criterion/kbcriterion" noneexistcriterionTypes "github.com/MaineK00n/vuls-data-update/pkg/extract/types/data/detection/condition/criteria/criterion/noneexistcriterion" necBinaryPackageTypes "github.com/MaineK00n/vuls-data-update/pkg/extract/types/data/detection/condition/criteria/criterion/noneexistcriterion/binary" versioncriterionTypes "github.com/MaineK00n/vuls-data-update/pkg/extract/types/data/detection/condition/criteria/criterion/versioncriterion" @@ -266,6 +267,82 @@ func Test_preConvert(t *testing.T) { }, }, }, + { + name: "windows -> microsoft with WindowsKB", + args: args{ + sr: &models.ScanResult{ + ServerName: "win-server", + Family: "windows", + Release: "Windows 10 Version 21H2 for x64-based Systems", + RunningKernel: models.Kernel{ + Version: "10.0.19044.1234", + }, + WindowsKB: &models.WindowsKB{ + Applied: []string{"5025288"}, + Unapplied: []string{"5025221"}, + }, + Packages: models.Packages{ + "Microsoft Edge": models.Package{ + Name: "Microsoft Edge", + Version: "128.0.2739.79", + }, + }, + }, + }, + want: scanTypes.ScanResult{ + JSONVersion: 0, + ServerName: "win-server", + Family: ecosystemTypes.EcosystemTypeMicrosoft, + Release: "Windows 10 Version 21H2 for x64-based Systems", + + Kernel: scanTypes.Kernel{ + Version: "10.0.19044.1234", + }, + OSPackages: []scanTypes.OSPackage{ + { + Name: "Microsoft Edge", + Version: "128.0.2739.79", + }, + { + Name: "Windows 10 Version 21H2 for x64-based Systems", + Version: "10.0.19044.1234", + }, + }, + MicrosoftKB: scanTypes.MicrosoftKB{ + Applied: []string{"5025288"}, + Unapplied: []string{"5025221"}, + }, + }, + }, + { + name: "windows without WindowsKB (nil)", + args: args{ + sr: &models.ScanResult{ + ServerName: "win-server-no-kb", + Family: "windows", + Release: "Windows Server 2019", + RunningKernel: models.Kernel{ + Version: "10.0.17763.1234", + }, + }, + }, + want: scanTypes.ScanResult{ + JSONVersion: 0, + ServerName: "win-server-no-kb", + Family: ecosystemTypes.EcosystemTypeMicrosoft, + Release: "Windows Server 2019", + + Kernel: scanTypes.Kernel{ + Version: "10.0.17763.1234", + }, + OSPackages: []scanTypes.OSPackage{ + { + Name: "Windows Server 2019", + Version: "10.0.17763.1234", + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -8497,6 +8574,125 @@ func Test_postConvert(t *testing.T) { }, }, }, + { + name: "microsoft kb detection", + args: args{ + scanned: scanTypes.ScanResult{ + Family: ecosystemTypes.EcosystemTypeMicrosoft, + Release: "Windows 10 Version 21H2 for x64-based Systems", + MicrosoftKB: scanTypes.MicrosoftKB{ + Applied: []string{"5025288"}, + Unapplied: []string{"5025221"}, + }, + }, + detected: detectTypes.DetectResult{ + Detected: []detectTypes.VulnerabilityData{ + { + ID: "CVE-2025-21234", + Vulnerabilities: []dbTypes.VulnerabilityDataVulnerability{ + { + ID: "CVE-2025-21234", + Contents: map[sourceTypes.SourceID]map[dataTypes.RootID][]vulnerabilityTypes.Vulnerability{ + sourceTypes.MicrosoftCVRF: { + dataTypes.RootID("CVE-2025-21234"): []vulnerabilityTypes.Vulnerability{ + { + Content: vulnerabilityContentTypes.Content{ + ID: "CVE-2025-21234", + Title: "Windows Win32k Elevation of Privilege Vulnerability", + Description: "A privilege escalation vulnerability.", + Severity: []severityTypes.Severity{ + { + Type: severityTypes.SeverityTypeCVSSv31, + CVSSv31: new(cvssV31Types.CVSSv31{ + Vector: "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + BaseScore: 7.8, + BaseSeverity: "HIGH", + }), + }, + }, + Published: new(time.Date(2025, 5, 13, 0, 0, 0, 0, time.UTC)), + }, + Segments: []segmentTypes.Segment{ + { + Ecosystem: ecosystemTypes.EcosystemTypeMicrosoft, + }, + }, + }, + }, + }, + }, + }, + }, + Detections: []detectTypes.VulnerabilityDataDetection{ + { + Ecosystem: ecosystemTypes.EcosystemTypeMicrosoft, + Contents: map[sourceTypes.SourceID][]conditionTypes.FilteredCondition{ + sourceTypes.MicrosoftCVRF: { + { + Criteria: criteriaTypes.FilteredCriteria{ + Operator: criteriaTypes.CriteriaOperatorTypeOR, + Criterions: []criterionTypes.FilteredCriterion{ + { + Criterion: criterionTypes.Criterion{ + Type: criterionTypes.CriterionTypeKB, + KB: &kbcriterionTypes.Criterion{ + Product: "Windows 10 Version 21H2 for x64-based Systems", + KBID: "5025221", + }, + }, + Accepts: criterionTypes.AcceptQueries{ + KB: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: models.VulnInfos{ + "CVE-2025-21234": { + CveID: "CVE-2025-21234", + Confidences: models.Confidences{models.WindowsUpdateSearch}, + AffectedPackages: models.PackageFixStatuses{ + { + Name: "Windows 10 Version 21H2 for x64-based Systems", + FixedIn: "KB5025221", + NotFixedYet: true, + }, + }, + DistroAdvisories: models.DistroAdvisories{ + { + AdvisoryID: "KB5025221", + Description: "Microsoft Knowledge Base", + }, + }, + WindowsKBFixedIns: []string{"5025221"}, + CveContents: models.CveContents{ + models.Microsoft: []models.CveContent{ + { + Type: models.Microsoft, + CveID: "CVE-2025-21234", + Title: "Windows Win32k Elevation of Privilege Vulnerability", + Summary: "A privilege escalation vulnerability.", + Cvss3Score: 7.8, + Cvss3Vector: "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + Cvss3Severity: "HIGH", + SourceLink: "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-21234", + Published: time.Date(2025, 5, 13, 0, 0, 0, 0, time.UTC), + LastModified: time.Date(1000, time.January, 1, 0, 0, 0, 0, time.UTC), + Optional: map[string]string{"vuls2-sources": `[{"root_id":"CVE-2025-21234","source_id":"microsoft-cvrf","segment":{"ecosystem":"microsoft"}}]`}, + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/go.mod b/go.mod index 7adfa89104..4ab3e94845 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4 github.com/BurntSushi/toml v1.6.0 github.com/CycloneDX/cyclonedx-go v0.10.0 - github.com/MaineK00n/vuls-data-update v0.0.0-20260312024807-b59af426d836 + github.com/MaineK00n/vuls-data-update v0.0.0-20260401073927-36c62680c94a github.com/MaineK00n/vuls2 v0.0.1-alpha.0.20260309062902-6fa3e81762d9 github.com/Ullaakut/nmap/v2 v2.2.2 github.com/aquasecurity/trivy v0.69.2 @@ -85,6 +85,7 @@ require ( github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect github.com/MaineK00n/go-cisco-version v0.0.0-20250909032920-fe1559e481f8 // indirect + github.com/MaineK00n/go-microsoft-version v0.0.0-20260325021654-1d9206bdeffc // indirect github.com/MaineK00n/go-paloalto-version v0.0.0-20250909032857-57479910413b // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect @@ -93,7 +94,7 @@ require ( github.com/Masterminds/squirrel v1.5.4 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProtonMail/go-crypto v1.3.0 // indirect - github.com/PuerkitoBio/goquery v1.11.0 // indirect + github.com/PuerkitoBio/goquery v1.12.0 // indirect github.com/VividCortex/ewma v1.2.0 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/agnivade/levenshtein v1.2.1 // indirect @@ -168,7 +169,7 @@ require ( github.com/go-errors/errors v1.4.2 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.8.0 // indirect - github.com/go-git/go-git/v5 v5.17.1 // indirect + github.com/go-git/go-git/v5 v5.17.2 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-jose/go-jose/v4 v4.1.3 // indirect @@ -229,7 +230,7 @@ require ( github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect github.com/kevinburke/ssh_config v1.4.0 // indirect - github.com/klauspost/compress v1.18.4 // indirect + github.com/klauspost/compress v1.18.5 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect @@ -288,7 +289,7 @@ require ( github.com/prometheus/common v0.67.4 // indirect github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect - github.com/redis/rueidis v1.0.70 // indirect + github.com/redis/rueidis v1.0.73 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rubenv/sql-migrate v1.8.0 // indirect @@ -375,10 +376,10 @@ require ( k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect k8s.io/kubectl v0.34.0 // indirect k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d // indirect - modernc.org/libc v1.67.6 // indirect + modernc.org/libc v1.70.0 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect - modernc.org/sqlite v1.46.1 // indirect + modernc.org/sqlite v1.48.1 // indirect mvdan.cc/sh/v3 v3.12.0 // indirect oras.land/oras-go/v2 v2.6.0 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect @@ -388,3 +389,7 @@ require ( sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) + +replace github.com/MaineK00n/vuls-data-update => ../vuls-data-update + +replace github.com/MaineK00n/vuls2 => ../vuls2 diff --git a/go.sum b/go.sum index 712af85ce0..bf595feba7 100644 --- a/go.sum +++ b/go.sum @@ -66,12 +66,10 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapp github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= github.com/MaineK00n/go-cisco-version v0.0.0-20250909032920-fe1559e481f8 h1:pmeRi+CPxx8R7KFQmZtY3WVTy4tnj31NGJ6OWI8Qy3g= github.com/MaineK00n/go-cisco-version v0.0.0-20250909032920-fe1559e481f8/go.mod h1:x/MwTByToVra1edsHGAGR+t1NsIiY1/PBa6B3hz3nDA= +github.com/MaineK00n/go-microsoft-version v0.0.0-20260325021654-1d9206bdeffc h1:ZeayjCT6JMMfoL9cS3w1BvBogxRi+I3QmabI8jL7+HQ= +github.com/MaineK00n/go-microsoft-version v0.0.0-20260325021654-1d9206bdeffc/go.mod h1:GNf+Vhnxk8/pW56jsxAeFCBP0VCgVQlLIJ812UnAj9c= github.com/MaineK00n/go-paloalto-version v0.0.0-20250909032857-57479910413b h1:pDmxa1+HCq7nShTgLURMOpjKc38hYq3lrgNHqur/Nps= github.com/MaineK00n/go-paloalto-version v0.0.0-20250909032857-57479910413b/go.mod h1:ELOxzfAd4oAe4niMmoZlSiJwzf1DF+DjNdjsUcuqAR8= -github.com/MaineK00n/vuls-data-update v0.0.0-20260312024807-b59af426d836 h1:yECaiXrWbjFpiNx9UjtAUwD54QuNM85upcFzwyN8cU0= -github.com/MaineK00n/vuls-data-update v0.0.0-20260312024807-b59af426d836/go.mod h1:SOEa6SbXQRsFSgH0WHz1uApgTw8tDyKUYT1T9HRtVUQ= -github.com/MaineK00n/vuls2 v0.0.1-alpha.0.20260309062902-6fa3e81762d9 h1:soWhB4NG12vsdy7N+LFxeVu5vS2YrHAuae+O/ZqPKqM= -github.com/MaineK00n/vuls2 v0.0.1-alpha.0.20260309062902-6fa3e81762d9/go.mod h1:Px7Z7+l1+WrZlhfVRRKW2rSZ8CqS4ZW6wb5/BsPCvBs= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= @@ -87,8 +85,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= -github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw= -github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ= +github.com/PuerkitoBio/goquery v1.12.0 h1:pAcL4g3WRXekcB9AU/y1mbKez2dbY2AajVhtkO8RIBo= +github.com/PuerkitoBio/goquery v1.12.0/go.mod h1:802ej+gV2y7bbIhOIoPY5sT183ZW0YFofScC4q/hIpQ= github.com/Ullaakut/nmap/v2 v2.2.2 h1:178Ety3d8T21sF6WZxyj7QVZUhnC1tL1J+tHLLW507Q= github.com/Ullaakut/nmap/v2 v2.2.2/go.mod h1:/6YyiW1Rgn7J6DAWCgL4CZZf6zJCFhB07PQzvjFfzLI= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= @@ -343,8 +341,8 @@ github.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDz github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.17.1 h1:WnljyxIzSj9BRRUlnmAU35ohDsjRK0EKmL0evDqi5Jk= -github.com/go-git/go-git/v5 v5.17.1/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo= +github.com/go-git/go-git/v5 v5.17.2 h1:B+nkdlxdYrvyFK4GPXVU8w1U+YkbsgciIR7f2sZJ104= +github.com/go-git/go-git/v5 v5.17.2/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= @@ -560,8 +558,8 @@ github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRt github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= -github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= +github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f h1:GvCU5GXhHq+7LeOzx/haG7HSIZokl3/0GkoUFzsRJjg= @@ -770,8 +768,8 @@ github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ= github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= -github.com/redis/rueidis v1.0.70 h1:O01v0Mt27/qXV9mKU/zahgxHdC8piHzIepqW4Nyzn/I= -github.com/redis/rueidis v1.0.70/go.mod h1:lfdcZzJ1oKGKL37vh9fO3ymwt+0TdjkkUCJxbgpmcgQ= +github.com/redis/rueidis v1.0.73 h1:0Enrg0VuMdaYyNDDj0lLIheWY0uybCeQOh+jTp2GG3M= +github.com/redis/rueidis v1.0.73/go.mod h1:lfdcZzJ1oKGKL37vh9fO3ymwt+0TdjkkUCJxbgpmcgQ= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo= @@ -1178,18 +1176,18 @@ k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d h1:wAhiDyZ4Tdtt7e46e9M5ZSAJ/MnPG k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= -modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc= -modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM= -modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= -modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= +modernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw= +modernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0= +modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM= +modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= -modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE= -modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= +modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= -modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI= -modernc.org/libc v1.67.6/go.mod h1:JAhxUVlolfYDErnwiqaLvUqc8nfb2r6S6slAgZOnaiE= +modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw= +modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= @@ -1198,8 +1196,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.46.1 h1:eFJ2ShBLIEnUWlLy12raN0Z1plqmFX9Qe3rjQTKt6sU= -modernc.org/sqlite v1.46.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA= +modernc.org/sqlite v1.48.1 h1:S85iToyU6cgeojybE2XJlSbcsvcWkQ6qqNXJHtW5hWA= +modernc.org/sqlite v1.48.1/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/gost/gost.go b/gost/gost.go index 665ca044e0..2a38f2c31b 100644 --- a/gost/gost.go +++ b/gost/gost.go @@ -68,8 +68,6 @@ func NewGostClient(cnf config.GostConf, family string, o logging.LogOpts) (Clien base := Base{driver: db, baseURL: cnf.GetURL()} switch family { - case constant.Windows: - return Microsoft{base}, nil case constant.ServerTypePseudo: return Pseudo{base}, nil default: diff --git a/gost/microsoft.go b/gost/microsoft.go deleted file mode 100644 index b9c743cd9b..0000000000 --- a/gost/microsoft.go +++ /dev/null @@ -1,435 +0,0 @@ -//go:build !scanner - -package gost - -import ( - "cmp" - "encoding/json" - "fmt" - "maps" - "net/http" - "slices" - "strconv" - "strings" - "time" - - "github.com/cenkalti/backoff" - "github.com/hashicorp/go-version" - "github.com/parnurzeal/gorequest" - "golang.org/x/xerrors" - - "github.com/future-architect/vuls/config" - "github.com/future-architect/vuls/logging" - "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" - gostmodels "github.com/vulsio/gost/models" -) - -// Microsoft is Gost client for windows -type Microsoft struct { - Base -} - -// DetectCVEs fills cve information that has in Gost -func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) { - var applied, unapplied []string - if r.WindowsKB != nil { - applied = r.WindowsKB.Applied - unapplied = r.WindowsKB.Unapplied - } - if ms.driver == nil { - u, err := util.URLPathJoin(ms.baseURL, "microsoft", "kbs") - if err != nil { - return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err) - } - - content := map[string]any{"applied": applied, "unapplied": unapplied} - var body []byte - var errs []error - var resp *http.Response - f := func() error { - req := gorequest.New().Post(u).SendStruct(content).Type("json") - if config.Conf.Gost.TimeoutSecPerRequest > 0 { - req = req.Timeout(time.Duration(config.Conf.Gost.TimeoutSecPerRequest) * time.Second) - } - resp, body, errs = req.EndBytes() - if 0 < len(errs) || resp == nil || resp.StatusCode != 200 { - return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %+v", u, resp, errs) - } - return nil - } - notify := func(err error, t time.Duration) { - logging.Log.Warnf("Failed to HTTP POST. retrying in %f seconds. err: %+v", t.Seconds(), err) - } - if err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify); err != nil { - return 0, xerrors.Errorf("HTTP Error: %w", err) - } - - var r struct { - Applied []string `json:"applied"` - Unapplied []string `json:"unapplied"` - } - if err := json.Unmarshal(body, &r); err != nil { - return 0, xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err) - } - applied = r.Applied - unapplied = r.Unapplied - } else { - applied, unapplied, err = ms.driver.GetExpandKB(applied, unapplied) - if err != nil { - return 0, xerrors.Errorf("Failed to detect CVEs. err: %w", err) - } - } - - var products []string - if ms.driver == nil { - u, err := util.URLPathJoin(ms.baseURL, "microsoft", "products") - if err != nil { - return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err) - } - - content := map[string]any{"release": r.Release, "kbs": append(applied, unapplied...)} - var body []byte - var errs []error - var resp *http.Response - f := func() error { - req := gorequest.New().Post(u).SendStruct(content).Type("json") - if config.Conf.Gost.TimeoutSecPerRequest > 0 { - req = req.Timeout(time.Duration(config.Conf.Gost.TimeoutSecPerRequest) * time.Second) - } - resp, body, errs = req.EndBytes() - if 0 < len(errs) || resp == nil || resp.StatusCode != 200 { - return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %+v", u, resp, errs) - } - return nil - } - notify := func(err error, t time.Duration) { - logging.Log.Warnf("Failed to HTTP POST. retrying in %f seconds. err: %+v", t.Seconds(), err) - } - if err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify); err != nil { - return 0, xerrors.Errorf("HTTP Error: %w", err) - } - - if err := json.Unmarshal(body, &products); err != nil { - return 0, xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err) - } - } else { - ps, err := ms.driver.GetRelatedProducts(r.Release, append(applied, unapplied...)) - if err != nil { - return 0, xerrors.Errorf("Failed to detect CVEs. err: %w", err) - } - products = ps - } - - m := map[string]struct{}{} - for _, p := range products { - m[p] = struct{}{} - } - for _, n := range []string{"Microsoft Edge (Chromium-based)", fmt.Sprintf("Microsoft Edge on %s", r.Release), fmt.Sprintf("Microsoft Edge (Chromium-based) in IE Mode on %s", r.Release), fmt.Sprintf("Microsoft Edge (EdgeHTML-based) on %s", r.Release)} { - delete(m, n) - } - filtered := []string{r.Release} - for _, p := range r.Packages { - switch p.Name { - case "Microsoft Edge": - if ss := strings.Split(p.Version, "."); len(ss) > 0 { - v, err := strconv.ParseInt(ss[0], 10, 8) - if err != nil { - continue - } - if v > 44 { - filtered = append(filtered, "Microsoft Edge (Chromium-based)", fmt.Sprintf("Microsoft Edge on %s", r.Release), fmt.Sprintf("Microsoft Edge (Chromium-based) in IE Mode on %s", r.Release)) - } else { - filtered = append(filtered, fmt.Sprintf("Microsoft Edge on %s", r.Release), fmt.Sprintf("Microsoft Edge (EdgeHTML-based) on %s", r.Release)) - } - } - default: - } - } - filtered = unique(append(filtered, slices.Collect(maps.Keys(m))...)) - - var cves map[string]gostmodels.MicrosoftCVE - if ms.driver == nil { - u, err := util.URLPathJoin(ms.baseURL, "microsoft", "filtered-cves") - if err != nil { - return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err) - } - - content := map[string]any{"products": filtered, "kbs": append(applied, unapplied...)} - var body []byte - var errs []error - var resp *http.Response - f := func() error { - req := gorequest.New().Post(u).SendStruct(content).Type("json") - if config.Conf.Gost.TimeoutSecPerRequest > 0 { - req = req.Timeout(time.Duration(config.Conf.Gost.TimeoutSecPerRequest) * time.Second) - } - resp, body, errs = req.EndBytes() - if 0 < len(errs) || resp == nil || resp.StatusCode != 200 { - return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %+v", u, resp, errs) - } - return nil - } - notify := func(err error, t time.Duration) { - logging.Log.Warnf("Failed to HTTP POST. retrying in %f seconds. err: %+v", t.Seconds(), err) - } - if err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify); err != nil { - return 0, xerrors.Errorf("HTTP Error: %w", err) - } - - if err := json.Unmarshal(body, &cves); err != nil { - return 0, xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err) - } - } else { - cves, err = ms.driver.GetFilteredCvesMicrosoft(filtered, append(applied, unapplied...)) - if err != nil { - return 0, xerrors.Errorf("Failed to detect CVEs. err: %w", err) - } - } - - for cveID, cve := range cves { - v, err := ms.detect(r, cve, applied, unapplied) - if err != nil { - return 0, xerrors.Errorf("Failed to detect. err: %w", err) - } - if v == nil { - continue - } - nCVEs++ - r.ScannedCves[cveID] = *v - } - return nCVEs, nil -} - -func (ms Microsoft) detect(r *models.ScanResult, cve gostmodels.MicrosoftCVE, applied, unapplied []string) (*models.VulnInfo, error) { - cve.Products = func() []gostmodels.MicrosoftProduct { - var ps []gostmodels.MicrosoftProduct - for _, p := range cve.Products { - if len(p.KBs) == 0 { - switch { - case p.Name == r.Release: - ps = append(ps, p) - case strings.HasPrefix(p.Name, "Microsoft Edge"): - ps = append(ps, p) - default: - } - continue - } - - p.KBs = func() []gostmodels.MicrosoftKB { - var kbs []gostmodels.MicrosoftKB - for _, kb := range p.KBs { - if _, err := strconv.Atoi(kb.Article); err != nil { - switch { - case strings.HasPrefix(p.Name, "Microsoft Edge"): - p, ok := r.Packages["Microsoft Edge"] - if !ok { - break - } - - if kb.FixedBuild == "" { - kbs = append(kbs, kb) - break - } - - vera, err := version.NewVersion(p.Version) - if err != nil { - kbs = append(kbs, kb) - break - } - verb, err := version.NewVersion(kb.FixedBuild) - if err != nil { - kbs = append(kbs, kb) - break - } - if vera.LessThan(verb) { - kbs = append(kbs, kb) - } - default: - } - } else { - if slices.Contains(applied, kb.Article) { - return nil - } - if slices.Contains(unapplied, kb.Article) { - kbs = append(kbs, kb) - } - } - } - return kbs - }() - if len(p.KBs) > 0 { - ps = append(ps, p) - } - } - return ps - }() - if len(cve.Products) == 0 { - return nil, nil - } - - cveCont, mitigations := ms.ConvertToModel(&cve) - vinfo := models.VulnInfo{ - CveID: cve.CveID, - CveContents: models.NewCveContents(*cveCont), - Mitigations: mitigations, - } - - for _, p := range cve.Products { - if len(p.KBs) == 0 { - switch { - case p.Name == r.Release: - vinfo.AffectedPackages = append(vinfo.AffectedPackages, models.PackageFixStatus{ - Name: p.Name, - FixState: "unfixed", - }) - case strings.HasPrefix(p.Name, "Microsoft Edge"): - vinfo.AffectedPackages = append(vinfo.AffectedPackages, models.PackageFixStatus{ - Name: "Microsoft Edge", - FixState: "unknown", - }) - default: - return nil, xerrors.Errorf("unexpected product. expected: %q, actual: %q", []string{r.Release, "Microsoft Edge"}, p.Name) - } - continue - } - - for _, kb := range p.KBs { - if _, err := strconv.Atoi(kb.Article); err != nil { - switch { - case strings.HasPrefix(p.Name, "Microsoft Edge"): - vinfo.AffectedPackages = append(vinfo.AffectedPackages, models.PackageFixStatus{ - Name: "Microsoft Edge", - FixState: func() string { - if func() bool { - if kb.FixedBuild == "" { - return true - } - - if _, err := version.NewVersion(r.Packages["Microsoft Edge"].Version); err != nil { - return true - } - - if _, err := version.NewVersion(kb.FixedBuild); err != nil { - return true - } - - return false - }() { - return "unknown" - } - return "fixed" - }(), - FixedIn: kb.FixedBuild, - }) - default: - return nil, xerrors.Errorf("unexpected product. supported: %q, actual: %q", []string{"Microsoft Edge"}, p.Name) - } - } else { - kbid := fmt.Sprintf("KB%s", kb.Article) - vinfo.DistroAdvisories.AppendIfMissing(new(models.DistroAdvisory{ - AdvisoryID: kbid, - Description: "Microsoft Knowledge Base", - })) - if !slices.Contains(vinfo.WindowsKBFixedIns, kbid) { - vinfo.WindowsKBFixedIns = append(vinfo.WindowsKBFixedIns, kbid) - } - } - } - } - - confs, err := func() (models.Confidences, error) { - var cs models.Confidences - - if len(vinfo.WindowsKBFixedIns) > 0 { - cs.AppendIfMissing(models.WindowsUpdateSearch) - } - - for _, stat := range vinfo.AffectedPackages { - switch stat.FixState { - case "fixed", "unfixed": - cs.AppendIfMissing(models.WindowsUpdateSearch) - case "unknown": - cs.AppendIfMissing(models.WindowsRoughMatch) - default: - return nil, xerrors.Errorf("unexpected fix state. expected: %q, actual: %q", []string{"fixed", "unfixed", "unknown"}, stat.FixState) - } - } - - if len(cs) == 0 { - return nil, xerrors.New("confidences not found") - } - return cs, nil - }() - if err != nil { - return nil, xerrors.Errorf("Failed to detect confidences. err: %w", err) - } - vinfo.Confidences = confs - - return &vinfo, nil -} - -// ConvertToModel converts gost model to vuls model -func (ms Microsoft) ConvertToModel(cve *gostmodels.MicrosoftCVE) (*models.CveContent, []models.Mitigation) { - slices.SortFunc(cve.Products, func(i, j gostmodels.MicrosoftProduct) int { - return cmp.Compare(i.ScoreSet.Vector, j.ScoreSet.Vector) - }) - - p := slices.MaxFunc(cve.Products, func(a, b gostmodels.MicrosoftProduct) int { - va, erra := strconv.ParseFloat(a.ScoreSet.BaseScore, 64) - vb, errb := strconv.ParseFloat(b.ScoreSet.BaseScore, 64) - if erra != nil { - if errb != nil { - return 0 - } - return -1 - } - if errb != nil { - return +1 - } - return cmp.Compare(va, vb) - }) - - var mitigations []models.Mitigation - if cve.Mitigation != "" { - mitigations = append(mitigations, models.Mitigation{ - CveContentType: models.Microsoft, - Mitigation: cve.Mitigation, - URL: cve.URL, - }) - } - if cve.Workaround != "" { - mitigations = append(mitigations, models.Mitigation{ - CveContentType: models.Microsoft, - Mitigation: cve.Workaround, - URL: cve.URL, - }) - } - - return &models.CveContent{ - Type: models.Microsoft, - CveID: cve.CveID, - Title: cve.Title, - Summary: cve.Description, - Cvss3Score: func() float64 { - v, err := strconv.ParseFloat(p.ScoreSet.BaseScore, 64) - if err != nil { - return 0.0 - } - return v - }(), - Cvss3Vector: p.ScoreSet.Vector, - Cvss3Severity: p.Severity, - Published: cve.PublishDate, - LastModified: cve.LastUpdateDate, - SourceLink: cve.URL, - Optional: func() map[string]string { - if 0 < len(cve.ExploitStatus) { - // TODO: CVE-2020-0739 - // "exploit_status": "Publicly Disclosed:No;Exploited:No;Latest Software Release:Exploitation Less Likely;Older Software Release:Exploitation Less Likely;DOS:N/A", - return map[string]string{"exploit": cve.ExploitStatus} - } - return nil - }(), - }, mitigations -} diff --git a/gost/microsoft_test.go b/gost/microsoft_test.go deleted file mode 100644 index 8fa49af60d..0000000000 --- a/gost/microsoft_test.go +++ /dev/null @@ -1,459 +0,0 @@ -//go:build !scanner - -package gost - -import ( - "reflect" - "testing" - - "github.com/future-architect/vuls/constant" - "github.com/future-architect/vuls/models" - gostmodels "github.com/vulsio/gost/models" -) - -func TestMicrosoft_detect(t *testing.T) { - type args struct { - r *models.ScanResult - cve gostmodels.MicrosoftCVE - applied []string - unapplied []string - } - tests := []struct { - name string - args args - want *models.VulnInfo - wantErr bool - }{ - { - name: "microsoft windows not affected", - args: args{ - r: &models.ScanResult{ - Family: constant.Windows, - Release: "Windows Server 2012 R2", - }, - cve: gostmodels.MicrosoftCVE{ - CveID: "CVE-2023-21554", - Products: []gostmodels.MicrosoftProduct{ - { - Name: "Windows Server 2012 R2", - KBs: []gostmodels.MicrosoftKB{ - { - Article: "5025285", - FixedBuild: "6.3.9600.20919", - }, - { - Article: "5025288", - FixedBuild: "6.3.9600.20919", - }, - }, - }, - }, - }, - applied: []string{"5025288"}, - }, - }, - { - name: "microsoft windows not affected2", - args: args{ - r: &models.ScanResult{ - Family: constant.Windows, - Release: "Windows 10 Version 21H2 for x64-based Systems", - }, - cve: gostmodels.MicrosoftCVE{ - CveID: "CVE-2023-21554", - Products: []gostmodels.MicrosoftProduct{ - { - Name: "Windows 10 Version 21H2 for x64-based Systems", - KBs: []gostmodels.MicrosoftKB{ - { - Article: "5025221", - FixedBuild: "10.0.19044.2846", - }, - }, - }, - }, - }, - unapplied: []string{"5026361"}, - }, - }, - { - name: "microsoft windows fixed", - args: args{ - r: &models.ScanResult{ - Family: constant.Windows, - Release: "Windows 10 Version 21H2 for x64-based Systems", - }, - cve: gostmodels.MicrosoftCVE{ - CveID: "CVE-2023-21554", - Products: []gostmodels.MicrosoftProduct{ - { - Name: "Windows 10 Version 21H2 for x64-based Systems", - KBs: []gostmodels.MicrosoftKB{ - { - Article: "5025221", - FixedBuild: "10.0.19044.2846", - }, - }, - }, - }, - }, - unapplied: []string{"5025221"}, - }, - want: &models.VulnInfo{ - CveID: "CVE-2023-21554", - Confidences: models.Confidences{models.WindowsUpdateSearch}, - DistroAdvisories: models.DistroAdvisories{ - { - AdvisoryID: "KB5025221", - Description: "Microsoft Knowledge Base", - }, - }, - CveContents: models.CveContents{ - models.Microsoft: []models.CveContent{ - { - Type: models.Microsoft, - CveID: "CVE-2023-21554", - }, - }, - }, - WindowsKBFixedIns: []string{"KB5025221"}, - }, - }, - { - name: "microsoft windows unfixed", - args: args{ - r: &models.ScanResult{ - Family: constant.Windows, - Release: "Windows 10 Version 21H2 for x64-based Systems", - }, - cve: gostmodels.MicrosoftCVE{ - CveID: "CVE-2013-3900", - Products: []gostmodels.MicrosoftProduct{ - { - Name: "Windows 10 Version 21H2 for x64-based Systems", - }, - }, - }, - }, - want: &models.VulnInfo{ - CveID: "CVE-2013-3900", - Confidences: models.Confidences{models.WindowsUpdateSearch}, - AffectedPackages: models.PackageFixStatuses{ - { - Name: "Windows 10 Version 21H2 for x64-based Systems", - FixState: "unfixed", - }, - }, - CveContents: models.CveContents{ - models.Microsoft: []models.CveContent{ - { - Type: models.Microsoft, - CveID: "CVE-2013-3900", - }, - }, - }, - }, - }, - { - name: "microsoft edge not installed", - args: args{ - r: &models.ScanResult{ - Family: constant.Windows, - Release: "Windows 10 Version 21H2 for x64-based Systems", - }, - cve: gostmodels.MicrosoftCVE{ - CveID: "CVE-2024-8639", - Products: []gostmodels.MicrosoftProduct{ - { - Name: "Microsoft Edge (Chromium-based)", - KBs: []gostmodels.MicrosoftKB{ - { - Article: "Release Notes", - FixedBuild: "128.0.2739.79", - }, - }, - }, - }, - }, - }, - }, - { - name: "microsoft edge not affected", - args: args{ - r: &models.ScanResult{ - Family: constant.Windows, - Release: "Windows 10 Version 21H2 for x64-based Systems", - Packages: models.Packages{ - "Microsoft Edge": { - Name: "Microsoft Edge", - Version: "128.0.2739.79", - }, - }, - }, - cve: gostmodels.MicrosoftCVE{ - CveID: "CVE-2024-8639", - Products: []gostmodels.MicrosoftProduct{ - { - Name: "Microsoft Edge (Chromium-based)", - KBs: []gostmodels.MicrosoftKB{ - { - Article: "Release Notes", - FixedBuild: "128.0.2739.79", - }, - }, - }, - }, - }, - }, - }, - { - name: "microsoft edge fixed", - args: args{ - r: &models.ScanResult{ - Family: constant.Windows, - Release: "Windows Server 2016", - Packages: models.Packages{ - "Microsoft Edge": { - Name: "Microsoft Edge", - Version: "38.14393", - }, - }, - }, - cve: gostmodels.MicrosoftCVE{ - CveID: "CVE-2016-7195", - Products: []gostmodels.MicrosoftProduct{ - { - Name: "Internet Explorer 11 on Windows Server 2016", - KBs: []gostmodels.MicrosoftKB{ - { - Article: "3200970", - }, - }, - }, - { - Name: "Microsoft Edge (EdgeHTML-based) on Windows Server 2016", - KBs: []gostmodels.MicrosoftKB{ - { - Article: "3200970", - }, - }, - }, - }, - }, - unapplied: []string{"3200970"}, - }, - want: &models.VulnInfo{ - CveID: "CVE-2016-7195", - Confidences: models.Confidences{models.WindowsUpdateSearch}, - DistroAdvisories: models.DistroAdvisories{ - { - AdvisoryID: "KB3200970", - Description: "Microsoft Knowledge Base", - }, - }, - CveContents: models.CveContents{ - models.Microsoft: []models.CveContent{ - { - Type: models.Microsoft, - CveID: "CVE-2016-7195", - }, - }, - }, - WindowsKBFixedIns: []string{"KB3200970"}, - }, - }, - { - name: "microsoft edge fixed2", - args: args{ - r: &models.ScanResult{ - Family: constant.Windows, - Release: "Windows 10 Version 21H2 for x64-based Systems", - Packages: models.Packages{ - "Microsoft Edge": { - Name: "Microsoft Edge", - Version: "111.0.1661.41", - }, - }, - }, - cve: gostmodels.MicrosoftCVE{ - CveID: "CVE-2024-8639", - Products: []gostmodels.MicrosoftProduct{ - { - Name: "Microsoft Edge (Chromium-based)", - KBs: []gostmodels.MicrosoftKB{ - { - Article: "Release Notes", - FixedBuild: "128.0.2739.79", - }, - }, - }, - }, - }, - }, - want: &models.VulnInfo{ - CveID: "CVE-2024-8639", - Confidences: models.Confidences{models.WindowsUpdateSearch}, - AffectedPackages: models.PackageFixStatuses{ - { - Name: "Microsoft Edge", - FixState: "fixed", - FixedIn: "128.0.2739.79", - }, - }, - CveContents: models.CveContents{ - models.Microsoft: []models.CveContent{ - { - Type: models.Microsoft, - CveID: "CVE-2024-8639", - }, - }, - }, - }, - }, - { - name: "microsoft edge unknown", - args: args{ - r: &models.ScanResult{ - Family: constant.Windows, - Release: "Windows 10 Version 21H2 for x64-based Systems", - Packages: models.Packages{ - "Microsoft Edge": { - Name: "Microsoft Edge", - Version: "111.0.1661.41", - }, - }, - }, - cve: gostmodels.MicrosoftCVE{ - CveID: "CVE-2020-1195", - Products: []gostmodels.MicrosoftProduct{ - { - Name: "Microsoft Edge (Chromium-based)", - }, - }, - }, - }, - want: &models.VulnInfo{ - CveID: "CVE-2020-1195", - Confidences: models.Confidences{models.WindowsRoughMatch}, - AffectedPackages: models.PackageFixStatuses{ - { - Name: "Microsoft Edge", - FixState: "unknown", - }, - }, - CveContents: models.CveContents{ - models.Microsoft: []models.CveContent{ - { - Type: models.Microsoft, - CveID: "CVE-2020-1195", - }, - }, - }, - }, - }, - { - name: "microsoft edge unknown2", - args: args{ - r: &models.ScanResult{ - Family: constant.Windows, - Release: "Windows 10 Version 21H2 for x64-based Systems", - Packages: models.Packages{ - "Microsoft Edge": { - Name: "Microsoft Edge", - Version: "111.0.1661.41", - }, - }, - }, - cve: gostmodels.MicrosoftCVE{ - CveID: "CVE-2022-4135", - Products: []gostmodels.MicrosoftProduct{ - { - Name: "Microsoft Edge (Chromium-based)", - KBs: []gostmodels.MicrosoftKB{ - { - Article: "Release Notes", - }, - }, - }, - }, - }, - }, - want: &models.VulnInfo{ - CveID: "CVE-2022-4135", - Confidences: models.Confidences{models.WindowsRoughMatch}, - AffectedPackages: models.PackageFixStatuses{ - { - Name: "Microsoft Edge", - FixState: "unknown", - }, - }, - CveContents: models.CveContents{ - models.Microsoft: []models.CveContent{ - { - Type: models.Microsoft, - CveID: "CVE-2022-4135", - }, - }, - }, - }, - }, - { - name: "microsoft other product not support", - args: args{ - r: &models.ScanResult{ - Family: constant.Windows, - Release: "Windows 10 Version 21H2 for x64-based Systems", - Packages: models.Packages{ - "Microsoft Visual Studio Code": { - Name: "Microsoft Visual Studio Code", - Version: "1.76.0", - }, - }, - }, - cve: gostmodels.MicrosoftCVE{ - CveID: "CVE-2024-26165", - Products: []gostmodels.MicrosoftProduct{ - { - Name: "Visual Studio Code", - KBs: []gostmodels.MicrosoftKB{ - { - Article: "Release Notes", - FixedBuild: "1.87.2", - }, - }, - }, - }, - }, - }, - }, - { - name: "microsoft other product not support2", - args: args{ - r: &models.ScanResult{ - Family: constant.Windows, - Release: "Windows Server 2016", - }, - cve: gostmodels.MicrosoftCVE{ - CveID: "ADV200001", - Products: []gostmodels.MicrosoftProduct{ - { - Name: "Internet Explorer 11 on Windows Server 2016", - }, - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := (Microsoft{}).detect(tt.args.r, tt.args.cve, tt.args.applied, tt.args.unapplied) - if (err != nil) != tt.wantErr { - t.Errorf("Microsoft.detect() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Microsoft.detect() = %v, want %v", got, tt.want) - } - }) - } -}