[Endpoint] Sample data generator for endpoint app (#58936)

* scaffolding and notes.md

* add skeleton event generator to kibana

* add optional entityID param to generateEvent

* add tree generation

* add tests

* working tests

* fix up tests

* fix linting

* fix event types

* make process parent types consistent

* make generator match types

* move test resolver node out of common types

* fix random string generation

* fix typecheck errors

* remove extraneous stuff

* address PR comments

* add test for full resolver tree

* cleanup

* make tests clearer

* add seedrandom to endpoint plugin. contains DONOTMERGE example code

* remove robs test

* start replacing random with seedrandom

* use seeded random for uuidv4

* separate out IP randomization

* typecheck fixes

Co-authored-by: oatkiller <robert.austin@elastic.co>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
marshallmain 2020-03-10 12:31:57 -04:00 committed by GitHub
parent 0ed7176e4d
commit 435cb0b959
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 669 additions and 275 deletions

View file

@ -0,0 +1,168 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { EndpointDocGenerator, Event } from './generate_data';
interface Node {
events: Event[];
children: Node[];
parent_entity_id?: string;
}
describe('data generator', () => {
let generator: EndpointDocGenerator;
beforeEach(() => {
generator = new EndpointDocGenerator('seed');
});
it('creates the same documents with same random seed', () => {
const generator1 = new EndpointDocGenerator('seed');
const generator2 = new EndpointDocGenerator('seed');
const timestamp = new Date().getTime();
const metadata1 = generator1.generateEndpointMetadata(timestamp);
const metadata2 = generator2.generateEndpointMetadata(timestamp);
expect(metadata1).toEqual(metadata2);
});
it('creates different documents with different random seeds', () => {
const generator1 = new EndpointDocGenerator('seed');
const generator2 = new EndpointDocGenerator('different seed');
const timestamp = new Date().getTime();
const metadata1 = generator1.generateEndpointMetadata(timestamp);
const metadata2 = generator2.generateEndpointMetadata(timestamp);
expect(metadata1).not.toEqual(metadata2);
});
it('creates endpoint metadata documents', () => {
const timestamp = new Date().getTime();
const metadata = generator.generateEndpointMetadata(timestamp);
expect(metadata['@timestamp']).toEqual(timestamp);
expect(metadata.event.created).toEqual(timestamp);
expect(metadata.endpoint).not.toBeNull();
expect(metadata.agent).not.toBeNull();
expect(metadata.host).not.toBeNull();
});
it('creates alert event documents', () => {
const timestamp = new Date().getTime();
const alert = generator.generateAlert(timestamp);
expect(alert['@timestamp']).toEqual(timestamp);
expect(alert.event.action).not.toBeNull();
expect(alert.endpoint).not.toBeNull();
expect(alert.agent).not.toBeNull();
expect(alert.host).not.toBeNull();
expect(alert.process.entity_id).not.toBeNull();
});
it('creates process event documents', () => {
const timestamp = new Date().getTime();
const processEvent = generator.generateEvent({ timestamp });
expect(processEvent['@timestamp']).toEqual(timestamp);
expect(processEvent.event.category).toEqual('process');
expect(processEvent.event.kind).toEqual('event');
expect(processEvent.event.type).toEqual('creation');
expect(processEvent.agent).not.toBeNull();
expect(processEvent.host).not.toBeNull();
expect(processEvent.process.entity_id).not.toBeNull();
});
it('creates other event documents', () => {
const timestamp = new Date().getTime();
const processEvent = generator.generateEvent({ timestamp, eventCategory: 'dns' });
expect(processEvent['@timestamp']).toEqual(timestamp);
expect(processEvent.event.category).toEqual('dns');
expect(processEvent.event.kind).toEqual('event');
expect(processEvent.event.type).toEqual('creation');
expect(processEvent.agent).not.toBeNull();
expect(processEvent.host).not.toBeNull();
expect(processEvent.process.entity_id).not.toBeNull();
});
describe('creates alert ancestor tree', () => {
let events: Event[];
beforeEach(() => {
events = generator.generateAlertEventAncestry(3);
});
it('with n-1 process events', () => {
for (let i = 1; i < events.length - 1; i++) {
expect(events[i].process.parent?.entity_id).toEqual(events[i - 1].process.entity_id);
expect(events[i].event.kind).toEqual('event');
expect(events[i].event.category).toEqual('process');
}
});
it('with a corresponding alert at the end', () => {
// The alert should be last and have the same entity_id as the previous process event
expect(events[events.length - 1].process.entity_id).toEqual(
events[events.length - 2].process.entity_id
);
expect(events[events.length - 1].process.parent?.entity_id).toEqual(
events[events.length - 2].process.parent?.entity_id
);
expect(events[events.length - 1].event.kind).toEqual('alert');
expect(events[events.length - 1].event.category).toEqual('malware');
});
});
function buildResolverTree(events: Event[]): Node {
// First pass we gather up all the events by entity_id
const tree: Record<string, Node> = {};
events.forEach(event => {
if (event.process.entity_id in tree) {
tree[event.process.entity_id].events.push(event);
} else {
tree[event.process.entity_id] = {
events: [event],
children: [],
parent_entity_id: event.process.parent?.entity_id,
};
}
});
// Second pass add child references to each node
for (const value of Object.values(tree)) {
if (value.parent_entity_id) {
tree[value.parent_entity_id].children.push(value);
}
}
// The root node must be first in the array or this fails
return tree[events[0].process.entity_id];
}
function countResolverEvents(rootNode: Node, generations: number): number {
// Start at the root, traverse N levels of the tree and check that we found all nodes
let nodes = [rootNode];
let visitedEvents = 0;
for (let i = 0; i < generations + 1; i++) {
let nextNodes: Node[] = [];
nodes.forEach(node => {
nextNodes = nextNodes.concat(node.children);
visitedEvents += node.events.length;
});
nodes = nextNodes;
}
return visitedEvents;
}
it('creates tree of process children', () => {
const timestamp = new Date().getTime();
const root = generator.generateEvent({ timestamp });
const generations = 2;
const events = generator.generateDescendantsTree(root, generations);
const rootNode = buildResolverTree(events);
const visitedEvents = countResolverEvents(rootNode, generations);
expect(visitedEvents).toEqual(events.length);
});
it('creates full resolver tree', () => {
const alertAncestors = 3;
const generations = 2;
const events = generator.generateFullResolverTree(alertAncestors, generations);
const rootNode = buildResolverTree(events);
const visitedEvents = countResolverEvents(rootNode, alertAncestors + generations);
expect(visitedEvents).toEqual(events.length);
});
});

View file

@ -0,0 +1,431 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import uuid from 'uuid';
import seedrandom from 'seedrandom';
import { AlertEvent, EndpointEvent, EndpointMetadata, OSFields } from './types';
export type Event = AlertEvent | EndpointEvent;
interface EventOptions {
timestamp?: number;
entityID?: string;
parentEntityID?: string;
eventType?: string;
eventCategory?: string;
}
const Windows: OSFields[] = [
{
name: 'windows 10.0',
full: 'Windows 10',
version: '10.0',
variant: 'Windows Pro',
},
{
name: 'windows 10.0',
full: 'Windows Server 2016',
version: '10.0',
variant: 'Windows Server',
},
{
name: 'windows 6.2',
full: 'Windows Server 2012',
version: '6.2',
variant: 'Windows Server',
},
{
name: 'windows 6.3',
full: 'Windows Server 2012R2',
version: '6.3',
variant: 'Windows Server Release 2',
},
];
const Linux: OSFields[] = [];
const Mac: OSFields[] = [];
const OS: OSFields[] = [...Windows, ...Mac, ...Linux];
const POLICIES: Array<{ name: string; id: string }> = [
{
name: 'Default',
id: '00000000-0000-0000-0000-000000000000',
},
{
name: 'With Eventing',
id: 'C2A9093E-E289-4C0A-AA44-8C32A414FA7A',
},
];
const FILE_OPERATIONS: string[] = ['creation', 'open', 'rename', 'execution', 'deletion'];
// These are from the v1 schemas and aren't all valid ECS event categories, still in flux
const OTHER_EVENT_CATEGORIES: string[] = ['driver', 'file', 'library', 'network', 'registry'];
export class EndpointDocGenerator {
agentId: string;
hostId: string;
hostname: string;
macAddress: string[];
ip: string[];
agentVersion: string;
os: OSFields;
policy: { name: string; id: string };
random: seedrandom.prng;
constructor(seed = Math.random().toString()) {
this.random = seedrandom(seed);
this.hostId = this.seededUUIDv4();
this.agentId = this.seededUUIDv4();
this.hostname = this.randomHostname();
this.ip = this.randomArray(3, () => this.randomIP());
this.macAddress = this.randomArray(3, () => this.randomMac());
this.agentVersion = this.randomVersion();
this.os = this.randomChoice(OS);
this.policy = this.randomChoice(POLICIES);
}
public randomizeIPs() {
this.ip = this.randomArray(3, () => this.randomIP());
}
public generateEndpointMetadata(ts = new Date().getTime()): EndpointMetadata {
return {
'@timestamp': ts,
event: {
created: ts,
},
endpoint: {
policy: {
id: this.policy.id,
},
},
agent: {
version: this.agentVersion,
id: this.agentId,
},
host: {
id: this.hostId,
hostname: this.hostname,
ip: this.ip,
mac: this.macAddress,
os: this.os,
},
};
}
public generateAlert(
ts = new Date().getTime(),
entityID = this.randomString(10),
parentEntityID?: string
): AlertEvent {
return {
'@timestamp': ts,
agent: {
id: this.agentId,
version: this.agentVersion,
},
event: {
action: this.randomChoice(FILE_OPERATIONS),
kind: 'alert',
category: 'malware',
id: this.seededUUIDv4(),
dataset: 'endpoint',
module: 'endpoint',
type: 'creation',
},
endpoint: {
policy: {
id: this.policy.id,
},
},
file: {
owner: 'SYSTEM',
name: 'fake_malware.exe',
path: 'C:/fake_malware.exe',
accessed: ts,
mtime: ts,
created: ts,
size: 3456,
hash: {
md5: 'fake file md5',
sha1: 'fake file sha1',
sha256: 'fake file sha256',
},
code_signature: {
trusted: false,
subject_name: 'bad signer',
},
malware_classifier: {
identifier: 'endpointpe',
score: 1,
threshold: 0.66,
version: '3.0.33',
},
temp_file_path: 'C:/temp/fake_malware.exe',
},
host: {
id: this.hostId,
hostname: this.hostname,
ip: this.ip,
mac: this.macAddress,
os: this.os,
},
process: {
pid: 2,
name: 'malware writer',
start: ts,
uptime: 0,
user: 'SYSTEM',
entity_id: entityID,
executable: 'C:/malware.exe',
parent: parentEntityID ? { entity_id: parentEntityID, pid: 1 } : undefined,
token: {
domain: 'NT AUTHORITY',
integrity_level: 16384,
integrity_level_name: 'system',
privileges: [
{
description: 'Replace a process level token',
enabled: false,
name: 'SeAssignPrimaryTokenPrivilege',
},
],
sid: 'S-1-5-18',
type: 'tokenPrimary',
user: 'SYSTEM',
},
code_signature: {
trusted: false,
subject_name: 'bad signer',
},
hash: {
md5: 'fake md5',
sha1: 'fake sha1',
sha256: 'fake sha256',
},
},
dll: [
{
pe: {
architecture: 'x64',
imphash: 'c30d230b81c734e82e86e2e2fe01cd01',
},
code_signature: {
subject_name: 'Cybereason Inc',
trusted: true,
},
compile_time: 1534424710,
hash: {
md5: '1f2d082566b0fc5f2c238a5180db7451',
sha1: 'ca85243c0af6a6471bdaa560685c51eefd6dbc0d',
sha256: '8ad40c90a611d36eb8f9eb24fa04f7dbca713db383ff55a03aa0f382e92061a2',
},
malware_classifier: {
identifier: 'Whitelisted',
score: 0,
threshold: 0,
version: '3.0.0',
},
mapped_address: 5362483200,
mapped_size: 0,
path: 'C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe',
},
],
};
}
public generateEvent(options: EventOptions = {}): EndpointEvent {
return {
'@timestamp': options.timestamp ? options.timestamp : new Date().getTime(),
agent: {
id: this.agentId,
version: this.agentVersion,
type: 'endpoint',
},
ecs: {
version: '1.4.0',
},
event: {
category: options.eventCategory ? options.eventCategory : 'process',
kind: 'event',
type: options.eventType ? options.eventType : 'creation',
id: this.seededUUIDv4(),
},
host: {
id: this.hostId,
hostname: this.hostname,
ip: this.ip,
mac: this.macAddress,
os: this.os,
},
process: {
entity_id: options.entityID ? options.entityID : this.randomString(10),
parent: options.parentEntityID ? { entity_id: options.parentEntityID } : undefined,
},
};
}
public generateFullResolverTree(
alertAncestors?: number,
childGenerations?: number,
maxChildrenPerNode?: number,
relatedEventsPerNode?: number,
percentNodesWithRelated?: number,
percentChildrenTerminated?: number
): Event[] {
const ancestry = this.generateAlertEventAncestry(alertAncestors);
// ancestry will always have at least 2 elements, and the second to last element will be the process associated with the alert
const descendants = this.generateDescendantsTree(
ancestry[ancestry.length - 2],
childGenerations,
maxChildrenPerNode,
relatedEventsPerNode,
percentNodesWithRelated,
percentChildrenTerminated
);
return ancestry.concat(descendants);
}
public generateAlertEventAncestry(alertAncestors = 3): Event[] {
const events = [];
const startDate = new Date().getTime();
const root = this.generateEvent({ timestamp: startDate + 1000 });
events.push(root);
let ancestor = root;
for (let i = 0; i < alertAncestors; i++) {
ancestor = this.generateEvent({
timestamp: startDate + 1000 * (i + 1),
parentEntityID: ancestor.process.entity_id,
});
events.push(ancestor);
}
events.push(
this.generateAlert(
startDate + 1000 * alertAncestors,
ancestor.process.entity_id,
ancestor.process.parent?.entity_id
)
);
return events;
}
public generateDescendantsTree(
root: Event,
generations = 2,
maxChildrenPerNode = 2,
relatedEventsPerNode = 3,
percentNodesWithRelated = 100,
percentChildrenTerminated = 100
): Event[] {
let events: Event[] = [root];
let parents = [root];
let timestamp = root['@timestamp'];
for (let i = 0; i < generations; i++) {
const newParents: EndpointEvent[] = [];
parents.forEach(element => {
// const numChildren = randomN(maxChildrenPerNode);
const numChildren = maxChildrenPerNode;
for (let j = 0; j < numChildren; j++) {
timestamp = timestamp + 1000;
const child = this.generateEvent({
timestamp,
parentEntityID: element.process.entity_id,
});
newParents.push(child);
}
});
events = events.concat(newParents);
parents = newParents;
}
const terminationEvents: EndpointEvent[] = [];
let relatedEvents: EndpointEvent[] = [];
events.forEach(element => {
if (this.randomN(100) < percentChildrenTerminated) {
timestamp = timestamp + 1000;
terminationEvents.push(
this.generateEvent({
timestamp,
entityID: element.process.entity_id,
parentEntityID: element.process.parent?.entity_id,
eventCategory: 'process',
eventType: 'end',
})
);
}
if (this.randomN(100) < percentNodesWithRelated) {
relatedEvents = relatedEvents.concat(
this.generateRelatedEvents(element, relatedEventsPerNode)
);
}
});
events = events.concat(terminationEvents);
events = events.concat(relatedEvents);
return events;
}
public generateRelatedEvents(node: Event, numRelatedEvents = 10): EndpointEvent[] {
const ts = node['@timestamp'] + 1000;
const relatedEvents: EndpointEvent[] = [];
for (let i = 0; i < numRelatedEvents; i++) {
relatedEvents.push(
this.generateEvent({
timestamp: ts,
entityID: node.process.entity_id,
parentEntityID: node.process.parent?.entity_id,
eventCategory: this.randomChoice(OTHER_EVENT_CATEGORIES),
})
);
}
return relatedEvents;
}
private randomN(n: number): number {
return Math.floor(this.random() * n);
}
private *randomNGenerator(max: number, count: number) {
while (count > 0) {
yield this.randomN(max);
count--;
}
}
private randomArray<T>(lengthLimit: number, generator: () => T): T[] {
const rand = this.randomN(lengthLimit) + 1;
return [...Array(rand).keys()].map(generator);
}
private randomMac(): string {
return [...this.randomNGenerator(255, 6)].map(x => x.toString(16)).join('-');
}
private randomIP(): string {
return [10, ...this.randomNGenerator(255, 3)].map(x => x.toString()).join('.');
}
private randomVersion(): string {
return [6, ...this.randomNGenerator(10, 2)].map(x => x.toString()).join('.');
}
private randomChoice<T>(choices: T[]): T {
return choices[this.randomN(choices.length)];
}
private randomString(length: number): string {
return [...this.randomNGenerator(36, length)].map(x => x.toString(36)).join('');
}
private randomHostname(): string {
return `Host-${this.randomString(10)}`;
}
private seededUUIDv4(): string {
return uuid.v4({ random: [...this.randomNGenerator(255, 16)] });
}
}

View file

@ -167,29 +167,34 @@ export type AlertEvent = Immutable<{
module: string;
type: string;
};
endpoint: {
policy: {
id: string;
};
};
process: {
code_signature: {
subject_name: string;
trusted: boolean;
};
command_line: string;
domain: string;
command_line?: string;
domain?: string;
pid: number;
ppid: number;
ppid?: number;
entity_id: string;
parent: {
parent?: {
pid: number;
entity_id: string;
};
name: string;
hash: HashFields;
pe: {
pe?: {
imphash: string;
};
executable: string;
sid: string;
sid?: string;
start: number;
malware_classifier: MalwareClassifierFields;
malware_classifier?: MalwareClassifierFields;
token: {
domain: string;
type: string;
@ -197,9 +202,9 @@ export type AlertEvent = Immutable<{
sid: string;
integrity_level: number;
integrity_level_name: string;
privileges: PrivilegesFields[];
privileges?: PrivilegesFields[];
};
thread: ThreadFields[];
thread?: ThreadFields[];
uptime: number;
user: string;
};
@ -212,32 +217,20 @@ export type AlertEvent = Immutable<{
created: number;
size: number;
hash: HashFields;
pe: {
pe?: {
imphash: string;
};
code_signature: {
trusted: boolean;
subject_name: string;
};
malware_classifier: {
features: {
data: {
buffer: string;
decompressed_size: number;
encoding: string;
};
};
} & MalwareClassifierFields;
malware_classifier: MalwareClassifierFields;
temp_file_path: string;
};
host: HostFields;
thread: {};
dll: DllFields[];
dll?: DllFields[];
}>;
/**
* Metadata associated with an alert event.
*/
interface AlertMetadata {
id: string;
@ -252,9 +245,9 @@ interface AlertMetadata {
export type AlertData = AlertEvent & AlertMetadata;
export interface EndpointMetadata {
'@timestamp': string;
'@timestamp': number;
event: {
created: Date;
created: number;
};
endpoint: {
policy: {
@ -262,8 +255,8 @@ export interface EndpointMetadata {
};
};
agent: {
version: string;
id: string;
version: string;
};
host: HostFields;
}
@ -310,22 +303,32 @@ export interface LegacyEndpointEvent {
export interface EndpointEvent {
'@timestamp': number;
agent: {
id: string;
version: string;
type: string;
};
ecs: {
version: string;
};
event: {
category: string;
type: string;
id: string;
kind: string;
};
endpoint: {
process: {
entity_id: string;
parent: {
entity_id: string;
};
};
};
agent: {
host: {
id: string;
type: string;
hostname: string;
ip: string[];
mac: string[];
os: OSFields;
};
process: {
entity_id: string;
parent?: {
entity_id: string;
};
};
}

View file

@ -6,9 +6,11 @@
"license": "Elastic-License",
"scripts": {},
"dependencies": {
"react-redux": "^7.1.0"
"react-redux": "^7.1.0",
"seedrandom": "^3.0.5"
},
"devDependencies": {
"@types/seedrandom": ">=2.0.0 <4.0.0",
"@types/react-redux": "^7.1.0",
"redux-devtools-extension": "^2.13.8"
}

View file

@ -5,6 +5,7 @@
*/
import { AlertResultList } from '../../../../../common/types';
import { EndpointDocGenerator } from '../../../../../common/generate_data';
export const mockAlertResultList: (options?: {
total?: number;
@ -24,160 +25,15 @@ export const mockAlertResultList: (options?: {
const actualCountToReturn = Math.max(Math.min(total - numberToSkip, requestPageSize), 0);
const alerts = [];
const generator = new EndpointDocGenerator();
for (let index = 0; index < actualCountToReturn; index++) {
alerts.push({
'@timestamp': 1542341895000,
id: 'xDUYMHABAJk0XnHd8rrd',
agent: {
id: 'ced9c68e-b94a-4d66-bb4c-6106514f0a2f',
version: '3.0.0',
...generator.generateAlert(new Date().getTime() + index * 1000),
...{
id: 'xDUYMHABAJk0XnHd8rrd' + index,
prev: null,
next: null,
},
host: {
id: 'xrctvybuni',
hostname: 'HD-c15-bc09190a',
ip: ['10.179.244.14'],
mac: ['xsertcyvbunimkn56edtyf'],
os: {
full: 'Windows 10',
name: 'windows',
version: '10',
variant: '3',
},
},
thread: {},
prev: null,
next: null,
event: {
id: '2f1c0928-3876-4e11-acbb-9199257c7b1c',
action: 'creation',
category: 'malware',
dataset: 'endpoint',
kind: 'alert',
module: 'endpoint',
type: 'creation',
},
file: {
accessed: 1542789400,
created: 1542789400,
hash: {
md5: '4ace3baaa509d08510405e1b169e325b',
sha1: '27fb21cf5db95ffca43b234affa99becc4023b9d',
sha256: '6ed1c836dbf099be7845bdab7671def2c157643761b52251e04e9b6ee109ec75',
},
pe: {
imphash: '835d619dfdf3cc727cebd91300ab3462',
},
mtime: 1542789400,
owner: 'Administrators',
name: 'test name',
path: 'C:\\Windows\\TEMP\\tmp0000008f\\tmp00001be5',
size: 188416,
code_signature: {
subject_name: 'Cybereason Inc',
trusted: false,
},
malware_classifier: {
features: {
data: {
buffer:
'eAHtnU1oHHUUwHsQ7MGDiIIUD4sH8WBBxJtopiLoUY0pYo2ZTbJJ0yQ17m4+ms/NRzeVWpuUWCL4sWlEYvFQ8KJQ6NCTEA8eRD30sIo3PdSriLi7837Pko3LbHZ2M5m+XObHm/d/X////83O7jCZvzacHBpPplNdfalkdjSdyty674Ft59dN71Dpb9v5eKh8LMEHjsCF2wIfVlRKsHROYPGkQO5+gY2vBSYYdWZFYGwEO/cITHMqkxPYnBBY+07gtCuQ9gSGigJ5lPPYGXcE+jA4z3Ad1ZtAUiDUyrEEPYzqRnIKgxd/Rgc7gygPo5wn95PouN7OeEYJ1UXiJgRmvscgp/LOziIkkSyT+xRVnXhZ4DKh5goCkzidRHkGO4uvCyw9LDDtCay8ILCAzrJOJaGuZwUuvSewivJVIPsklq8JbL4qMJsTSCcExrGs83WKU295ZFo5lr2TaZbcUw5FeJy8tgTeLpCy2iGeS67ABXzlgbEi1UC5FxcZnA4y/CLK82Qxi847FGGZRTLsCUxR1aWEwOp1AmOjDRYYzgwusL9WfqBiGJxnVAanixTq7Dp22LBdlWMJzlOx8wmBK2Rx5WmBLJIRwtAijOQE+ooCb2B5xBOYRtlfNeXpLpA7oyZRTqHzGenkmIJPnhBIMrzTwSA6H93CO5l+c1NA99f6IwLH8fUKdjTmDpTbgS50+gGVnECnE4PpooC2guPoaPADSHrcncNHmEHtAFkq3+EI+A37zsrrTvH3WTkvJLoOTyBp10wx2JcgVCRahA4NrICE4a+hrMXsA3qAHItW188E8ejO7XV3eh/KCYwxlamEwCgL8lN2wTntfrhY/U0g/5KAdvUpT+AszWqBdqH7VLeeZrExK9Cv1UgIDKA8g/cx7QAEP+AhAfRaMKB2HOJh+BSFSqKjSytNGBlc6PrpxvK7lCVDxbSG3Z7AhCMwx6gelwgLAltXBXJUTH29j+U1LHdipx/QprfKfGnF0sBpdBYxmEQyTzW0h6/0khcuhhJYRufym+i4VKMocJMs/KvfoW3/UJb4PeZOSZVONThZz4djP/75TAXa/CVfOvX3RgVLIDreLPN1pP1osW7lGmHsEhjBOzf+EPBE4vndvWz5xb/cChxGcv1LAb+tluALKnZ47isf1MXvz1ZMlsCXbXtPceqhrcp1ps6YHwQeBXLEPCf7q23tl9uJui0bGBgYRAccv7uXr/g5Af+2oNTrpgTa/vnpjBvpLAwM4gRBPvIZGBgYGBgYGBgYGBgYGBgYGBgYGBgYNAOc9oMXs4GBgYFBcNBnww5QzDXgRtPSaZ5lg/itsRaslgZ3bnWEEVnhMetIBwiiVnlbCbWrEftrt11zdwWnseFW1QO63w1is3ptD1pV9xG0t+zvfUrzrvh380qwXWAVCw6h78GIfG7ZlzltXu6hd+y92fECRFhjuH3bXG8N43oXEHperdzvUbteaDxhVTUeq25fqhG1X6Ai8mtF6BDXz2wR+dzSgg4Qsxls5T11XMG+82y8GkG+b7kL69xg7mF1SFvhBgYGsYH/Xi7HE+PVkiB2jt1bNZxT+k4558jR53ydz5//1m1KOgYGBgYGBgYGEQfnsYaG2z1sdPJS79XQSu91ndobOAHCaN5vNzUk1bceQVzUpbw3iOuT+UFmR18bHrp3gyhDC56lCd1y85w2+HSNUwVhhdGC7blLf+bV/fqtvhMg1NDjCcugB1QXswbs8ekj/v1BgzFHBIIsyP+HfwFdMpzu',
decompressed_size: 27831,
encoding: 'zlib',
},
},
identifier: 'endpointpe',
score: 1,
threshold: 0.66,
version: '3.0.33',
},
temp_file_path: 'C:\\Windows\\TEMP\\1bb9abfc-ca14-47b2-9f2c-10c323df42f9',
},
process: {
pid: 1076,
ppid: 432,
entity_id: 'wertqwer',
parent: {
pid: 432,
entity_id: 'adsfsdaf',
},
name: 'test name',
code_signature: {
subject_name: 'Cybereason Inc',
trusted: true,
},
command_line: '"C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe"',
domain: 'NT AUTHORITY',
executable: 'C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe',
hash: {
md5: '1f2d082566b0fc5f2c238a5180db7451',
sha1: 'ca85243c0af6a6471bdaa560685c51eefd6dbc0d',
sha256: '8ad40c90a611d36eb8f9eb24fa04f7dbca713db383ff55a03aa0f382e92061a2',
},
pe: {
imphash: 'c30d230b81c734e82e86e2e2fe01cd01',
},
malware_classifier: {
identifier: 'Whitelisted',
score: 0,
threshold: 0,
version: '3.0.0',
},
thread: [
{
id: 1652,
service_name: 'CybereasonAntiMalware',
start: 1542788400,
start_address: 8791698721056,
start_address_module: 'C:\\Program Files\\Cybereason ActiveProbe\\gzfltum.dll',
},
],
sid: 'S-1-5-18',
start: 1542788400,
token: {
domain: 'NT AUTHORITY',
integrity_level: 16384,
integrity_level_name: 'system',
privileges: [
{
description: 'Replace a process level token',
enabled: false,
name: 'SeAssignPrimaryTokenPrivilege',
},
],
sid: 'S-1-5-18',
type: 'tokenPrimary',
user: 'SYSTEM',
},
uptime: 1025,
user: 'SYSTEM',
},
dll: [
{
pe: {
architecture: 'x64',
imphash: 'c30d230b81c734e82e86e2e2fe01cd01',
},
code_signature: {
subject_name: 'Cybereason Inc',
trusted: true,
},
compile_time: 1534424710,
hash: {
md5: '1f2d082566b0fc5f2c238a5180db7451',
sha1: 'ca85243c0af6a6471bdaa560685c51eefd6dbc0d',
sha256: '8ad40c90a611d36eb8f9eb24fa04f7dbca713db383ff55a03aa0f382e92061a2',
},
malware_classifier: {
identifier: 'Whitelisted',
score: 0,
threshold: 0,
version: '3.0.0',
},
mapped_address: 5362483200,
mapped_size: 0,
path: 'C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe',
},
],
});
}
const mock: AlertResultList = {

View file

@ -7,44 +7,20 @@
import { createStore, Dispatch, Store } from 'redux';
import { ManagementAction, managementListReducer } from './index';
import { EndpointMetadata } from '../../../../../common/types';
import { EndpointDocGenerator } from '../../../../../common/generate_data';
import { ManagementListState } from '../../types';
import { listData } from './selectors';
describe('endpoint_list store concerns', () => {
let store: Store<ManagementListState>;
let dispatch: Dispatch<ManagementAction>;
const generator = new EndpointDocGenerator();
const createTestStore = () => {
store = createStore(managementListReducer);
dispatch = store.dispatch;
};
const generateEndpoint = (): EndpointMetadata => {
return {
'@timestamp': new Date(1582231151055).toString(),
event: {
created: new Date(0),
},
endpoint: {
policy: {
id: '',
},
},
agent: {
version: '',
id: '',
},
host: {
id: '',
hostname: '',
ip: [''],
mac: [''],
os: {
name: '',
full: '',
version: '',
variant: '',
},
},
};
return generator.generateEndpointMetadata(new Date().getTime());
};
const loadDataToStore = () => {
dispatch({

View file

@ -9,6 +9,7 @@ import { coreMock } from '../../../../../../../../src/core/public/mocks';
import { History, createBrowserHistory } from 'history';
import { managementListReducer, managementMiddlewareFactory } from './index';
import { EndpointMetadata, EndpointResultList } from '../../../../../common/types';
import { EndpointDocGenerator } from '../../../../../common/generate_data';
import { ManagementListState } from '../../types';
import { AppAction } from '../action';
import { listData } from './selectors';
@ -19,38 +20,14 @@ describe('endpoint list saga', () => {
let store: Store<ManagementListState>;
let getState: typeof store['getState'];
let dispatch: Dispatch<AppAction>;
let history: History<never>;
const generator = new EndpointDocGenerator();
// https://github.com/elastic/endpoint-app-team/issues/131
const generateEndpoint = (): EndpointMetadata => {
return {
'@timestamp': new Date(1582231151055).toString(),
event: {
created: new Date(0),
},
endpoint: {
policy: {
id: '',
},
},
agent: {
version: '',
id: '',
},
host: {
id: '',
hostname: '',
ip: [''],
mac: [''],
os: {
name: '',
full: '',
version: '',
variant: '',
},
},
};
return generator.generateEndpointMetadata(new Date().getTime());
};
let history: History<never>;
const getEndpointListApiResponse = (): EndpointResultList => {
return {
endpoints: [generateEndpoint()],

View file

@ -5,6 +5,7 @@
*/
import { EndpointResultList } from '../../../../../common/types';
import { EndpointDocGenerator } from '../../../../../common/generate_data';
export const mockHostResultList: (options?: {
total?: number;
@ -25,33 +26,8 @@ export const mockHostResultList: (options?: {
const endpoints = [];
for (let index = 0; index < actualCountToReturn; index++) {
endpoints.push({
'@timestamp': new Date(1582231151055).toString(),
event: {
created: new Date('2020-02-20T20:39:11.055Z'),
},
endpoint: {
policy: {
id: '00000000-0000-0000-0000-000000000000',
},
},
agent: {
version: '6.9.2',
id: '9a87fdac-e6c0-4f27-a25c-e349e7093cb1',
},
host: {
id: '3ca26fe5-1c7d-42b8-8763-98256d161c9f',
hostname: 'bea-0.example.com',
ip: ['10.154.150.114', '10.43.37.62', '10.217.73.149'],
mac: ['ea-5a-a8-c0-5-95', '7e-d8-fe-7f-b6-4e', '23-31-5d-af-e6-2b'],
os: {
name: 'windows 6.2',
full: 'Windows Server 2012',
version: '6.2',
variant: 'Windows Server Release 2',
},
},
});
const generator = new EndpointDocGenerator('seed');
endpoints.push(generator.generateEndpointMetadata());
}
const mock: EndpointResultList = {
endpoints,

View file

@ -51,13 +51,13 @@ export const SourceProcessAccordion = memo(({ alertData }: { alertData: Immutabl
title: i18n.translate('xpack.endpoint.application.endpoint.alertDetails.malwareScore', {
defaultMessage: 'MalwareScore',
}),
description: alertData.process.malware_classifier.score,
description: alertData.process.malware_classifier?.score || '-',
},
{
title: i18n.translate('xpack.endpoint.application.endpoint.alertDetails.parentProcessID', {
defaultMessage: 'Parent Process ID',
}),
description: alertData.process.parent.pid,
description: alertData.process.parent?.pid || '-',
},
{
title: i18n.translate('xpack.endpoint.application.endpoint.alertDetails.signer', {

View file

@ -21,7 +21,7 @@ export function extractEntityID(event: ResolverEvent) {
if (isLegacyData(event)) {
return String(event.endgame.unique_pid);
}
return event.endpoint.process.entity_id;
return event.process.entity_id;
}
export function extractParentEntityID(event: ResolverEvent) {
@ -29,5 +29,5 @@ export function extractParentEntityID(event: ResolverEvent) {
const ppid = event.endgame.unique_ppid;
return ppid && String(ppid); // if unique_ppid is undefined return undefined
}
return event.endpoint.process.parent?.entity_id;
return event.process.parent?.entity_id;
}

View file

@ -5169,6 +5169,11 @@
"@types/tough-cookie" "*"
form-data "^2.5.0"
"@types/seedrandom@>=2.0.0 <4.0.0":
version "2.4.28"
resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-2.4.28.tgz#9ce8fa048c1e8c85cb71d7fe4d704e000226036f"
integrity sha512-SMA+fUwULwK7sd/ZJicUztiPs8F1yCPwF3O23Z9uQ32ME5Ha0NmDK9+QTsYE4O2tHXChzXomSWWeIhCnoN1LqA==
"@types/selenium-webdriver@^4.0.5":
version "4.0.5"
resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.0.5.tgz#23041a4948c82daf2df9836e4d2358fec10d3e24"