Fixed false positive for msrc companion apps (#38824)
**Related issue:** Resolves #35281 - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Fixed false positives when detecting security vulnerabilities in Microsoft 365 companion apps by improving targeting accuracy. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1 @@
|
||||
* Fixed CVE false positives for Microsoft 365 companion apps by targeting Microsoft 365 better
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
@@ -22,10 +23,11 @@ var (
|
||||
// with a list of CVEs. These rules address false negatives in the NVD data.
|
||||
// Add an interface if you want to add more rule types.
|
||||
type CVEMatchingRule struct {
|
||||
NameLikeMatch string // Name of software to match (like match)
|
||||
SourceMatch string // Source of software to match (exact match)
|
||||
CVEs []string // List of CVEs to assign to software
|
||||
ResolvedInVersion string // Version of software that resolves the CVEs
|
||||
NameLikeMatch string // Name of software to match (like match)
|
||||
ExcludeIfNameContains string // Exclude software if name contains this pattern (case-insensitive, in-memory filter)
|
||||
SourceMatch string // Source of software to match (exact match)
|
||||
CVEs []string // List of CVEs to assign to software
|
||||
ResolvedInVersion string // Version of software that resolves the CVEs
|
||||
}
|
||||
|
||||
type CVEMatchingRules []CVEMatchingRule
|
||||
@@ -38,24 +40,27 @@ func getCVEMatchingRules() CVEMatchingRules {
|
||||
// June 11 2024 Office 365 Vulnerabilities
|
||||
// https://learn.microsoft.com/en-us/officeupdates/microsoft365-apps-security-updates
|
||||
{
|
||||
NameLikeMatch: "Microsoft 365",
|
||||
SourceMatch: "programs",
|
||||
CVEs: []string{"CVE-2024-30101", "CVE-2024-30102", "CVE-2024-30103", "CVE-2024-30104"},
|
||||
ResolvedInVersion: "16.0.17628.20144",
|
||||
NameLikeMatch: "Microsoft 365",
|
||||
ExcludeIfNameContains: "companion",
|
||||
SourceMatch: "programs",
|
||||
CVEs: []string{"CVE-2024-30101", "CVE-2024-30102", "CVE-2024-30103", "CVE-2024-30104"},
|
||||
ResolvedInVersion: "16.0.17628.20144",
|
||||
},
|
||||
// July 9 2024 Office 365 Vulnerabilities
|
||||
// https://learn.microsoft.com/en-us/officeupdates/microsoft365-apps-security-updates
|
||||
{
|
||||
NameLikeMatch: "Microsoft 365",
|
||||
SourceMatch: "programs",
|
||||
CVEs: []string{"CVE-2023-38545", "CVE-2024-38020", "CVE-2024-38021"},
|
||||
ResolvedInVersion: "16.0.17726.20160",
|
||||
NameLikeMatch: "Microsoft 365",
|
||||
ExcludeIfNameContains: "companion",
|
||||
SourceMatch: "programs",
|
||||
CVEs: []string{"CVE-2023-38545", "CVE-2024-38020", "CVE-2024-38021"},
|
||||
ResolvedInVersion: "16.0.17726.20160",
|
||||
},
|
||||
// August 13 2024 Office 365 Vulnerabilities
|
||||
// https://learn.microsoft.com/en-us/officeupdates/microsoft365-apps-security-updates
|
||||
{
|
||||
NameLikeMatch: "Microsoft 365",
|
||||
SourceMatch: "programs",
|
||||
NameLikeMatch: "Microsoft 365",
|
||||
ExcludeIfNameContains: "companion",
|
||||
SourceMatch: "programs",
|
||||
CVEs: []string{
|
||||
"CVE-2024-38172",
|
||||
"CVE-2024-38170",
|
||||
@@ -89,7 +94,17 @@ func (r CVEMatchingRule) match(ctx context.Context, ds fleet.Datastore) ([]fleet
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var excludePattern string
|
||||
if r.ExcludeIfNameContains != "" {
|
||||
excludePattern = strings.ToLower(r.ExcludeIfNameContains)
|
||||
}
|
||||
|
||||
for _, s := range software {
|
||||
// Skip software that matches the exclusion pattern
|
||||
if excludePattern != "" && strings.Contains(strings.ToLower(s.Name), excludePattern) {
|
||||
continue
|
||||
}
|
||||
|
||||
if nvd.SmartVerCmp(s.Version, r.ResolvedInVersion) < 0 {
|
||||
for _, cve := range r.CVEs {
|
||||
vulns = append(vulns, fleet.SoftwareVulnerability{
|
||||
|
||||
@@ -74,6 +74,72 @@ func TestMatchVersion(t *testing.T) {
|
||||
require.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestMatchExcludeIfNameContains(t *testing.T) {
|
||||
ds := new(mock.Store)
|
||||
|
||||
rule := CVEMatchingRule{
|
||||
NameLikeMatch: "Microsoft 365",
|
||||
ExcludeIfNameContains: "companion",
|
||||
SourceMatch: "programs",
|
||||
ResolvedInVersion: "16.0.17628.20144",
|
||||
CVEs: []string{"CVE-2024-001", "CVE-2024-002"},
|
||||
}
|
||||
|
||||
sw := []fleet.Software{
|
||||
{
|
||||
ID: 1,
|
||||
Name: "Microsoft 365 - en-us",
|
||||
Version: "16.0.17000.00000",
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
Name: "Microsoft 365 companion apps",
|
||||
Version: "2.2601.6000.0",
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
Name: "Microsoft 365 Companion Apps",
|
||||
Version: "2.2601.6000.0",
|
||||
},
|
||||
{
|
||||
ID: 4,
|
||||
Name: "Microsoft 365 - fr-fr",
|
||||
Version: "16.0.17000.00000",
|
||||
},
|
||||
}
|
||||
|
||||
expected := []fleet.SoftwareVulnerability{
|
||||
{
|
||||
SoftwareID: 1,
|
||||
CVE: "CVE-2024-001",
|
||||
ResolvedInVersion: ptr.String("16.0.17628.20144"),
|
||||
},
|
||||
{
|
||||
SoftwareID: 1,
|
||||
CVE: "CVE-2024-002",
|
||||
ResolvedInVersion: ptr.String("16.0.17628.20144"),
|
||||
},
|
||||
{
|
||||
SoftwareID: 4,
|
||||
CVE: "CVE-2024-001",
|
||||
ResolvedInVersion: ptr.String("16.0.17628.20144"),
|
||||
},
|
||||
{
|
||||
SoftwareID: 4,
|
||||
CVE: "CVE-2024-002",
|
||||
ResolvedInVersion: ptr.String("16.0.17628.20144"),
|
||||
},
|
||||
}
|
||||
|
||||
ds.ListSoftwareForVulnDetectionFunc = func(ctx context.Context, filter fleet.VulnSoftwareFilter) ([]fleet.Software, error) {
|
||||
return sw, nil
|
||||
}
|
||||
|
||||
actual, err := rule.match(context.Background(), ds)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestMatchFilters(t *testing.T) {
|
||||
ds := new(mock.Store)
|
||||
|
||||
@@ -236,12 +302,19 @@ func TestCheckCustomVulnerabilities(t *testing.T) {
|
||||
Version: "2.52.0",
|
||||
Source: "homebrew_packages",
|
||||
},
|
||||
// Microsoft 365 companion apps should be excluded from all matching rules
|
||||
{
|
||||
ID: 7,
|
||||
Name: "Microsoft 365 companion apps",
|
||||
Version: "2.2601.6000.0",
|
||||
Source: "programs",
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("New Vulns return all inserted", func(t *testing.T) {
|
||||
ds.ListSoftwareForVulnDetectionFunc = func(ctx context.Context, filter fleet.VulnSoftwareFilter) ([]fleet.Software, error) {
|
||||
if filter.Name == "Microsoft 365" && filter.Source == "programs" {
|
||||
return []fleet.Software{sw[0], sw[1], sw[2], sw[3]}, nil
|
||||
return []fleet.Software{sw[0], sw[1], sw[2], sw[3], sw[6]}, nil
|
||||
}
|
||||
if filter.Name == "git-gui" && filter.Source == "homebrew_packages" {
|
||||
return []fleet.Software{sw[4], sw[5]}, nil
|
||||
@@ -253,6 +326,7 @@ func TestCheckCustomVulnerabilities(t *testing.T) {
|
||||
ds.InsertSoftwareVulnerabilityFunc = func(ctx context.Context, vuln fleet.SoftwareVulnerability, source fleet.VulnerabilitySource) (bool, error) {
|
||||
insertCount++
|
||||
require.Equal(t, fleet.CustomSource, source)
|
||||
require.NotEqual(t, uint(7), vuln.SoftwareID, "Microsoft 365 companion apps should be excluded from CVE matching")
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -462,7 +536,7 @@ func TestCheckCustomVulnerabilities(t *testing.T) {
|
||||
|
||||
ds.ListSoftwareForVulnDetectionFunc = func(ctx context.Context, filter fleet.VulnSoftwareFilter) ([]fleet.Software, error) {
|
||||
if filter.Name == "Microsoft 365" && filter.Source == "programs" {
|
||||
return []fleet.Software{sw[0], sw[1], sw[2], sw[3]}, nil
|
||||
return []fleet.Software{sw[0], sw[1], sw[2], sw[3], sw[6]}, nil
|
||||
}
|
||||
if filter.Name == "git-gui" && filter.Source == "homebrew_packages" {
|
||||
return []fleet.Software{sw[4], sw[5]}, nil
|
||||
@@ -474,6 +548,7 @@ func TestCheckCustomVulnerabilities(t *testing.T) {
|
||||
ds.InsertSoftwareVulnerabilityFunc = func(ctx context.Context, vuln fleet.SoftwareVulnerability, source fleet.VulnerabilitySource) (bool, error) {
|
||||
insertCount++
|
||||
require.Equal(t, fleet.CustomSource, source)
|
||||
require.NotEqual(t, uint(7), vuln.SoftwareID, "Microsoft 365 companion apps should be excluded from CVE matching")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user