From 8b20cbc3d86d5398bb9bc07d7d12c66ee453ae15 Mon Sep 17 00:00:00 2001 From: Ross Wolf <31489089+rw-access@users.noreply.github.com> Date: Tue, 20 Apr 2021 14:25:21 -0400 Subject: [PATCH] [Security] Add telemetry for new protection types and arrays of objects (#97624) * Add telemetry for new protection types and arrays of objects * Add malware_signature to process.Ext + dll.Ext * Fix comments for base fields * Move naming convention disable to a line * Fix unit test for rule.version --- .../server/lib/telemetry/sender.test.ts | 53 +++++++++ .../server/lib/telemetry/sender.ts | 108 ++++++++++-------- 2 files changed, 113 insertions(+), 48 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/sender.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/sender.test.ts index b32d2a6542f4..f620027409d2 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/sender.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/sender.test.ts @@ -38,6 +38,7 @@ describe('TelemetryEventsSender', () => { id: 'X', name: 'Y', ruleset: 'Z', + version: '100', }, file: { size: 3, @@ -97,6 +98,7 @@ describe('TelemetryEventsSender', () => { id: 'X', name: 'Y', ruleset: 'Z', + version: '100', }, file: { size: 3, @@ -253,6 +255,57 @@ describe('allowlistEventFields', () => { }); }); + it('filters arrays of objects', () => { + const event = { + a: [ + { + a1: 'a1', + }, + ], + b: { + b1: 'b1', + }, + c: [ + { + d: 'd1', + e: 'e1', + f: 'f1', + }, + { + d: 'd2', + e: 'e2', + f: 'f2', + }, + { + d: 'd3', + e: 'e3', + f: 'f3', + }, + ], + }; + expect(copyAllowlistedFields(allowlist, event)).toStrictEqual({ + a: [ + { + a1: 'a1', + }, + ], + b: { + b1: 'b1', + }, + c: [ + { + d: 'd1', + }, + { + d: 'd2', + }, + { + d: 'd3', + }, + ], + }); + }); + it("doesn't create empty objects", () => { const event = { a: 'a', diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts index 7d723c578e3d..b47edbb21d17 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts @@ -21,16 +21,8 @@ import { } from '../../../../task_manager/server'; import { TelemetryDiagTask } from './task'; -export type SearchTypes = - | string - | string[] - | number - | number[] - | boolean - | boolean[] - | object - | object[] - | undefined; +type BaseSearchTypes = string | number | boolean | object; +export type SearchTypes = BaseSearchTypes | BaseSearchTypes[] | undefined; export interface TelemetryEvent { [key: string]: SearchTypes; @@ -294,8 +286,8 @@ interface AllowlistFields { } // Allow list process fields within events. This includes "process" and "Target.process".' -/* eslint-disable @typescript-eslint/naming-convention */ const allowlistProcessFields: AllowlistFields = { + args: true, name: true, executable: true, command_line: true, @@ -306,48 +298,23 @@ const allowlistProcessFields: AllowlistFields = { architecture: true, code_signature: true, dll: true, + malware_signature: true, token: { integrity_level_name: true, }, }, - parent: { - name: true, - executable: true, - command_line: true, - hash: true, - Ext: { - architecture: true, - code_signature: true, - dll: true, - token: { - integrity_level_name: true, - }, - }, - uptime: true, - pid: true, - ppid: true, - }, thread: true, }; -// Allow list for the data we include in the events. True means that it is deep-cloned -// blindly. Object contents means that we only copy the fields that appear explicitly in -// the sub-object. -const allowlistEventFields: AllowlistFields = { - '@timestamp': true, - agent: true, - Endpoint: true, - Memory_protection: true, - Ransomware: true, - data_stream: true, - ecs: true, - elastic: true, - event: true, - rule: { - id: true, +// Allow list for event-related fields, which can also be nested under events[] +const allowlistBaseEventFields: AllowlistFields = { + dll: { name: true, - ruleset: true, + path: true, + code_signature: true, + malware_signature: true, }, + event: true, file: { name: true, path: true, @@ -365,13 +332,52 @@ const allowlistEventFields: AllowlistFields = { quarantine_message: true, }, }, + process: { + parent: allowlistProcessFields, + ...allowlistProcessFields, + }, + network: { + direction: true, + }, + registry: { + hive: true, + key: true, + path: true, + value: true, + }, + Target: { + process: { + parent: allowlistProcessFields, + ...allowlistProcessFields, + }, + }, +}; + +// Allow list for the data we include in the events. True means that it is deep-cloned +// blindly. Object contents means that we only copy the fields that appear explicitly in +// the sub-object. +const allowlistEventFields: AllowlistFields = { + '@timestamp': true, + agent: true, + Endpoint: true, + /* eslint-disable @typescript-eslint/naming-convention */ + Memory_protection: true, + Ransomware: true, + data_stream: true, + ecs: true, + elastic: true, + // behavioral protection re-nests some field sets under events.* + events: allowlistBaseEventFields, + rule: { + id: true, + name: true, + ruleset: true, + version: true, + }, host: { os: true, }, - process: allowlistProcessFields, - Target: { - process: allowlistProcessFields, - }, + ...allowlistBaseEventFields, }; export function copyAllowlistedFields( @@ -383,6 +389,12 @@ export function copyAllowlistedFields( if (eventValue !== null && eventValue !== undefined) { if (allowValue === true) { return { ...newEvent, [allowKey]: eventValue }; + } else if (typeof allowValue === 'object' && Array.isArray(eventValue)) { + const subValues = eventValue.filter((v) => typeof v === 'object'); + return { + ...newEvent, + [allowKey]: subValues.map((v) => copyAllowlistedFields(allowValue, v as TelemetryEvent)), + }; } else if (typeof allowValue === 'object' && typeof eventValue === 'object') { const values = copyAllowlistedFields(allowValue, eventValue as TelemetryEvent); return {