Fix Windows Cloudflare WARP version ingestion (#14797)

#14522

- [X] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- ~[ ] Documented any API changes (docs/Using-Fleet/REST-API.md or
docs/Contributing/API-for-contributors.md)~
- ~[ ] Documented any permissions changes (docs/Using
Fleet/manage-access.md)~
- ~[ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)~
- ~[ ] Added support on fleet's osquery simulator `cmd/osquery-perf` for
new osquery data ingestion features.~
- [X] Added/updated tests
- [X] Manual QA for all new/changed functionality
  - ~For Orbit and Fleet Desktop changes:~
- ~[ ] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.~
- ~[ ] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).~
This commit is contained in:
Lucas Manuel Rodriguez 2023-10-30 19:41:16 -03:00 committed by GitHub
parent d76c9bf3c9
commit 75b17df6e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 109 additions and 5 deletions

View file

@ -0,0 +1 @@
* Fixed how Fleet ingest Windows' Cloudflare WARP software version.

View file

@ -1175,7 +1175,7 @@ func directIngestSoftware(ctx context.Context, logger log.Logger, host *fleet.Ho
level.Debug(logger).Log(
"msg", "host reported software with invalid last opened timestamp",
"host_id", host.ID,
"row", row,
"row", fmt.Sprintf("%+v", row),
)
}
@ -1194,13 +1194,13 @@ func directIngestSoftware(ctx context.Context, logger log.Logger, host *fleet.Ho
level.Debug(logger).Log(
"msg", "failed to parse software row",
"host_id", host.ID,
"row", row,
"row", fmt.Sprintf("%+v", row),
"err", err,
)
continue
}
sanitizeSoftware(host, s)
sanitizeSoftware(host, s, logger)
software = append(software, *s)
@ -1231,7 +1231,7 @@ var macOSMSTeamsVersion = regexp.MustCompile(`(\d).00.(\d)(\d+)`)
// sanitizeSoftware performs any sanitization required to the ingested software fields.
//
// Some fields are reported with known incorrect values and we need to fix them before using them.
func sanitizeSoftware(h *fleet.Host, s *fleet.Software) {
func sanitizeSoftware(h *fleet.Host, s *fleet.Software, logger log.Logger) {
softwareSanitizers := []struct {
checkSoftware func(*fleet.Host, *fleet.Software) bool
mutateSoftware func(*fleet.Software)
@ -1250,6 +1250,31 @@ func sanitizeSoftware(h *fleet.Host, s *fleet.Software) {
}
},
},
// In the Windows Registry, Cloudflare WARP defines its major version with the last two digits, e.g. `23.9.248.0`.
// On NVD, the vulnerabilities are reported using the full year, e.g. `2023.9.248.0`.
{
checkSoftware: func(h *fleet.Host, s *fleet.Software) bool {
return h.Platform == "windows" && s.Name == "Cloudflare WARP" && s.Source == "programs"
},
mutateSoftware: func(s *fleet.Software) {
// Perform some sanity check on the version before mutating it.
parts := strings.Split(s.Version, ".")
if len(parts) <= 1 {
level.Debug(logger).Log("msg", "failed to parse software version", "name", s.Name, "version", s.Version)
return
}
_, err := strconv.Atoi(parts[0])
if err != nil {
level.Debug(logger).Log("msg", "failed to parse software version", "name", s.Name, "version", s.Version, "err", err)
return
}
// In case Cloudflare starts returning the full year.
if len(parts[0]) == 4 {
return
}
s.Version = "20" + s.Version // Cloudflare WARP was released on 2019.
},
},
}
for _, softwareSanitizer := range softwareSanitizers {

View file

@ -1352,9 +1352,87 @@ func TestSanitizeSoftware(t *testing.T) {
Version: "1.2.3",
},
},
{
name: "Cloudflare WARP on Windows, version not using full year",
h: &fleet.Host{
Platform: "windows",
},
s: &fleet.Software{
Name: "Cloudflare WARP",
Version: "23.9.248.0",
Source: "programs",
},
sanitized: &fleet.Software{
Name: "Cloudflare WARP",
Version: "2023.9.248.0",
Source: "programs",
},
},
{
name: "Cloudflare WARP on Windows, version using full year",
h: &fleet.Host{
Platform: "windows",
},
s: &fleet.Software{
Name: "Cloudflare WARP",
Version: "2023.9.248.0",
Source: "programs",
},
sanitized: &fleet.Software{
Name: "Cloudflare WARP",
Version: "2023.9.248.0",
Source: "programs",
},
},
{
name: "Cloudflare WARP on Windows with invalid version",
h: &fleet.Host{
Platform: "windows",
},
s: &fleet.Software{
Name: "Cloudflare WARP",
Version: "foobar",
Source: "programs",
},
sanitized: &fleet.Software{
Name: "Cloudflare WARP",
Version: "foobar",
Source: "programs",
},
},
{
name: "Cloudflare WARP on Windows with invalid version",
h: &fleet.Host{
Platform: "windows",
},
s: &fleet.Software{
Name: "Cloudflare WARP",
Version: "foo.bar",
Source: "programs",
},
sanitized: &fleet.Software{
Name: "Cloudflare WARP",
Version: "foo.bar",
Source: "programs",
},
},
{
name: "Other on Windows",
h: &fleet.Host{
Platform: "windows",
},
s: &fleet.Software{
Name: "Other",
Version: "1.2.3",
},
sanitized: &fleet.Software{
Name: "Other",
Version: "1.2.3",
},
},
} {
t.Run(tc.name, func(t *testing.T) {
sanitizeSoftware(tc.h, tc.s)
sanitizeSoftware(tc.h, tc.s, log.NewNopLogger())
require.Equal(t, tc.sanitized, tc.s)
})
}