[Security Solution] Adds posix eventing model fields to generator script (#127207)

* Adds posix eventing model fields to generator script

* Fix types and update snapshot
This commit is contained in:
Kevin Qualters 2022-03-09 14:00:17 -05:00 committed by GitHub
parent 67e52e75fe
commit ca447c66ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 178 additions and 48 deletions

View file

@ -578,4 +578,16 @@ describe('data generator', () => {
const visitedEvents = countResolverEvents(rootNode, alertAncestors + generations);
expect(visitedEvents).toEqual(events.length);
});
it('creates full resolver tree with a single entry_leader id', () => {
const events = [...generator.alertsGenerator(1)];
const [rootEvent, ...children] = events;
expect(
children.every((event) => {
return (
event.process?.entry_leader?.entity_id === rootEvent.process?.entry_leader?.entity_id
);
})
).toBe(true);
});
});

View file

@ -346,6 +346,7 @@ export interface TreeOptions {
ancestryArraySize?: number;
eventsDataStream?: DataStream;
alertsDataStream?: DataStream;
sessionEntryLeader?: string;
}
type TreeOptionDefaults = Required<TreeOptions>;
@ -363,6 +364,7 @@ export function getTreeOptionsWithDef(options?: TreeOptions): TreeOptionDefaults
relatedEvents: options?.relatedEvents ?? 5,
relatedEventsOrdered: options?.relatedEventsOrdered ?? false,
relatedAlerts: options?.relatedAlerts ?? 3,
sessionEntryLeader: options?.sessionEntryLeader ?? '',
percentWithRelated: options?.percentWithRelated ?? 30,
percentTerminated: options?.percentTerminated ?? 100,
alwaysGenMaxChildrenPerNode: options?.alwaysGenMaxChildrenPerNode ?? false,
@ -535,12 +537,14 @@ export class EndpointDocGenerator extends BaseDataGenerator {
*/
public generateMalwareAlert({
ts = new Date().getTime(),
sessionEntryLeader = this.randomString(10),
entityID = this.randomString(10),
parentEntityID,
ancestry = [],
alertsDataStream = alertsDefaultDataStream,
}: {
ts?: number;
sessionEntryLeader?: string;
entityID?: string;
parentEntityID?: string;
ancestry?: string[];
@ -608,6 +612,21 @@ export class EndpointDocGenerator extends BaseDataGenerator {
sha1: 'fake sha1',
sha256: 'fake sha256',
},
entry_leader: {
entity_id: sessionEntryLeader,
name: 'fake entry',
pid: Math.floor(Math.random() * 1000),
},
session_leader: {
entity_id: sessionEntryLeader,
name: 'fake session',
pid: Math.floor(Math.random() * 1000),
},
group_leader: {
entity_id: sessionEntryLeader,
name: 'fake leader',
pid: Math.floor(Math.random() * 1000),
},
Ext: {
ancestry,
code_signature: [
@ -648,6 +667,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
*/
public generateMemoryAlert({
ts = new Date().getTime(),
sessionEntryLeader = this.randomString(10),
entityID = this.randomString(10),
parentEntityID,
ancestry = [],
@ -655,6 +675,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
alertType,
}: {
ts?: number;
sessionEntryLeader?: string;
entityID?: string;
parentEntityID?: string;
ancestry?: string[];
@ -701,6 +722,21 @@ export class EndpointDocGenerator extends BaseDataGenerator {
sha1: 'fake sha1',
sha256: 'fake sha256',
},
entry_leader: {
entity_id: sessionEntryLeader,
name: 'fake entry',
pid: Math.floor(Math.random() * 1000),
},
session_leader: {
entity_id: sessionEntryLeader,
name: 'fake session',
pid: Math.floor(Math.random() * 1000),
},
group_leader: {
entity_id: sessionEntryLeader,
name: 'fake leader',
pid: Math.floor(Math.random() * 1000),
},
Ext: {
ancestry,
code_signature: [
@ -758,12 +794,14 @@ export class EndpointDocGenerator extends BaseDataGenerator {
public generateAlert({
ts = new Date().getTime(),
entityID = this.randomString(10),
sessionEntryLeader,
parentEntityID,
ancestry = [],
alertsDataStream = alertsDefaultDataStream,
}: {
ts?: number;
entityID?: string;
sessionEntryLeader?: string;
parentEntityID?: string;
ancestry?: string[];
alertsDataStream?: DataStream;
@ -773,6 +811,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
case AlertTypes.MALWARE:
return this.generateMalwareAlert({
ts,
sessionEntryLeader,
entityID,
parentEntityID,
ancestry,
@ -783,6 +822,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
return this.generateMemoryAlert({
ts,
entityID,
sessionEntryLeader,
parentEntityID,
ancestry,
alertsDataStream,
@ -791,6 +831,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
case AlertTypes.BEHAVIOR:
return this.generateBehaviorAlert({
ts,
sessionEntryLeader,
entityID,
parentEntityID,
ancestry,
@ -811,12 +852,14 @@ export class EndpointDocGenerator extends BaseDataGenerator {
*/
public generateBehaviorAlert({
ts = new Date().getTime(),
sessionEntryLeader = this.randomString(10),
entityID = this.randomString(10),
parentEntityID,
ancestry = [],
alertsDataStream = alertsDefaultDataStream,
}: {
ts?: number;
sessionEntryLeader?: string;
entityID?: string;
parentEntityID?: string;
ancestry?: string[];
@ -878,6 +921,21 @@ export class EndpointDocGenerator extends BaseDataGenerator {
status: 'trusted',
subject_name: 'Microsoft Windows',
},
entry_leader: {
entity_id: sessionEntryLeader,
name: 'fake entry',
pid: Math.floor(Math.random() * 1000),
},
session_leader: {
entity_id: sessionEntryLeader,
name: 'fake session',
pid: Math.floor(Math.random() * 1000),
},
group_leader: {
entity_id: sessionEntryLeader,
name: 'fake leader',
pid: Math.floor(Math.random() * 1000),
},
parent: parentEntityID
? {
entity_id: parentEntityID,
@ -950,6 +1008,10 @@ export class EndpointDocGenerator extends BaseDataGenerator {
options.ancestry?.slice(0, options?.ancestryArrayLimit ?? ANCESTRY_LIMIT) ?? [];
const processName = options.processName ? options.processName : this.randomProcessName();
const sessionEntryLeader = options.sessionEntryLeader
? options.sessionEntryLeader
: this.randomString(10);
const userName = this.randomString(10);
const detailRecordForEventType =
options.extensions ||
((eventCategory) => {
@ -992,13 +1054,29 @@ export class EndpointDocGenerator extends BaseDataGenerator {
pid:
'pid' in options && typeof options.pid !== 'undefined' ? options.pid : this.randomN(5000),
executable: `C:\\${processName}`,
args: `"C:\\${processName}" \\${this.randomString(3)}`,
args: [`"C:\\${processName}"`, `--${this.randomString(3)}`],
working_directory: `/home/${userName}/`,
code_signature: {
status: 'trusted',
subject_name: 'Microsoft',
},
hash: { md5: this.seededUUIDv4() },
entity_id: options.entityID ? options.entityID : this.randomString(10),
entry_leader: {
entity_id: sessionEntryLeader,
name: 'fake entry',
pid: Math.floor(Math.random() * 1000),
},
session_leader: {
entity_id: sessionEntryLeader,
name: 'fake session',
pid: Math.floor(Math.random() * 1000),
},
group_leader: {
entity_id: sessionEntryLeader,
name: 'fake leader',
pid: Math.floor(Math.random() * 1000),
},
parent: options.parentEntityID
? {
entity_id: options.parentEntityID,
@ -1017,7 +1095,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
},
user: {
domain: this.randomString(10),
name: this.randomString(10),
name: userName,
},
};
}
@ -1179,7 +1257,9 @@ export class EndpointDocGenerator extends BaseDataGenerator {
public *alertsGenerator(numAlerts: number, options: TreeOptions = {}) {
const opts = getTreeOptionsWithDef(options);
for (let i = 0; i < numAlerts; i++) {
yield* this.fullResolverTreeGenerator(opts);
// 1 session per resolver tree
const sessionEntryLeader = this.randomString(10);
yield* this.fullResolverTreeGenerator({ ...opts, sessionEntryLeader });
}
}
@ -1222,8 +1302,11 @@ export class EndpointDocGenerator extends BaseDataGenerator {
const events = [];
const startDate = new Date().getTime();
const root = this.generateEvent({
timestamp: startDate + 1000,
entityID: opts.sessionEntryLeader,
sessionEntryLeader: opts.sessionEntryLeader,
eventsDataStream: opts.eventsDataStream,
});
events.push(root);
@ -1240,6 +1323,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
node,
relatedAlerts: alertsPerNode,
alertCreationTime: secBeforeAlert,
sessionEntryLeader: opts.sessionEntryLeader,
alertsDataStream: opts.alertsDataStream,
})) {
eventList.push(relatedAlert);
@ -1252,6 +1336,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
relatedEvents: opts.relatedEvents,
processDuration: secBeforeEvent,
ordered: opts.relatedEventsOrdered,
sessionEntryLeader: opts.sessionEntryLeader,
eventsDataStream: opts.eventsDataStream,
})) {
eventList.push(relatedEvent);
@ -1273,6 +1358,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
timestamp: timestamp + termProcessDuration * 1000,
entityID: entityIDSafeVersion(root),
parentEntityID: parentEntityIDSafeVersion(root),
sessionEntryLeader: opts.sessionEntryLeader,
eventCategory: ['process'],
eventType: ['end'],
eventsDataStream: opts.eventsDataStream,
@ -1292,6 +1378,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
ancestor = this.generateEvent({
timestamp,
parentEntityID: entityIDSafeVersion(ancestor),
sessionEntryLeader: opts.sessionEntryLeader,
// add the parent to the ancestry array
ancestry,
ancestryArrayLimit: opts.ancestryArraySize,
@ -1309,6 +1396,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
timestamp: timestamp + termProcessDuration * 1000,
entityID: entityIDSafeVersion(ancestor),
parentEntityID: parentEntityIDSafeVersion(ancestor),
sessionEntryLeader: opts.sessionEntryLeader,
eventCategory: ['process'],
eventType: ['end'],
ancestry: ancestryArray(ancestor),
@ -1339,6 +1427,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
ts: timestamp,
entityID: entityIDSafeVersion(ancestor),
parentEntityID: parentEntityIDSafeVersion(ancestor),
sessionEntryLeader: opts.sessionEntryLeader,
ancestry: ancestryArray(ancestor),
alertsDataStream: opts.alertsDataStream,
})
@ -1395,6 +1484,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
const child = this.generateEvent({
timestamp,
parentEntityID: currentStateEntityID,
sessionEntryLeader: opts.sessionEntryLeader,
ancestry,
ancestryArrayLimit: opts.ancestryArraySize,
eventsDataStream: opts.eventsDataStream,
@ -1416,6 +1506,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
yield this.generateEvent({
timestamp: timestamp + processDuration * 1000,
entityID: entityIDSafeVersion(child),
sessionEntryLeader: opts.sessionEntryLeader,
parentEntityID: parentEntityIDSafeVersion(child),
eventCategory: ['process'],
eventType: ['end'],
@ -1428,6 +1519,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
yield* this.relatedEventsGenerator({
node: child,
relatedEvents: opts.relatedEvents,
sessionEntryLeader: opts.sessionEntryLeader,
processDuration,
ordered: opts.relatedEventsOrdered,
eventsDataStream: opts.eventsDataStream,
@ -1435,6 +1527,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
yield* this.relatedAlertsGenerator({
node: child,
relatedAlerts: opts.relatedAlerts,
sessionEntryLeader: opts.sessionEntryLeader,
alertCreationTime: processDuration,
alertsDataStream: opts.alertsDataStream,
});
@ -1456,11 +1549,13 @@ export class EndpointDocGenerator extends BaseDataGenerator {
relatedEvents = 10,
processDuration = 6 * 3600,
ordered = false,
sessionEntryLeader,
eventsDataStream = eventsDefaultDataStream,
}: {
node: Event;
relatedEvents?: RelatedEventInfo[] | number;
processDuration?: number;
sessionEntryLeader: string;
ordered?: boolean;
eventsDataStream?: DataStream;
}) {
@ -1491,6 +1586,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
yield this.generateEvent({
timestamp: ts,
entityID: entityIDSafeVersion(node),
sessionEntryLeader,
parentEntityID: parentEntityIDSafeVersion(node),
eventCategory: eventInfo.category,
eventType: eventInfo.creationType,
@ -1512,17 +1608,20 @@ export class EndpointDocGenerator extends BaseDataGenerator {
relatedAlerts = 3,
alertCreationTime = 6 * 3600,
alertsDataStream = alertsDefaultDataStream,
sessionEntryLeader,
}: {
node: Event;
relatedAlerts: number;
alertCreationTime: number;
alertsDataStream: DataStream;
sessionEntryLeader: string;
}) {
for (let i = 0; i < relatedAlerts; i++) {
const ts = (timestampSafeVersion(node) ?? 0) + this.randomN(alertCreationTime) * 1000;
yield this.generateAlert({
ts,
entityID: entityIDSafeVersion(node),
sessionEntryLeader,
parentEntityID: parentEntityIDSafeVersion(node),
ancestry: ancestryArray(node),
alertsDataStream,

View file

@ -14,6 +14,7 @@ export interface EventOptions {
timestamp?: number;
entityID?: string;
parentEntityID?: string;
sessionEntryLeader?: string;
eventType?: string | string[];
eventCategory?: string | string[];
processName?: string;

View file

@ -739,11 +739,27 @@ export type SafeEndpointEvent = Partial<{
}>;
pid: ECSField<number>;
hash: Hashes;
working_directory: ECSField<string>;
parent: Partial<{
entity_id: ECSField<string>;
name: ECSField<string>;
pid: ECSField<number>;
}>;
session_leader: Partial<{
entity_id: ECSField<string>;
name: ECSField<string>;
pid: ECSField<number>;
}>;
entry_leader: Partial<{
entity_id: ECSField<string>;
name: ECSField<string>;
pid: ECSField<number>;
}>;
group_leader: Partial<{
entity_id: ECSField<string>;
name: ECSField<string>;
pid: ECSField<number>;
}>;
/*
* The array has a special format. The entity_ids towards the beginning of the array are closer ancestors and the
* values towards the end of the array are more distant ancestors (grandparents). Therefore

View file

@ -15,11 +15,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "A",
"process.name": "lsass.exe",
"process.name": "powershell.exe",
"process.parent.entity_id": "",
},
"id": "A",
"name": "lsass.exe",
"name": "powershell.exe",
"parent": undefined,
"stats": Object {
"byCategory": Object {},
@ -33,11 +33,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "A",
"process.name": "lsass.exe",
"process.name": "powershell.exe",
"process.parent.entity_id": "",
},
"id": "A",
"name": "lsass.exe",
"name": "powershell.exe",
"parent": undefined,
"stats": Object {
"byCategory": Object {},
@ -58,11 +58,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "A",
"process.name": "notepad.exe",
"process.name": "lsass.exe",
"process.parent.entity_id": "",
},
"id": "A",
"name": "notepad.exe",
"name": "lsass.exe",
"parent": undefined,
"stats": Object {
"byCategory": Object {},
@ -73,11 +73,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "B",
"process.name": "mimikatz.exe",
"process.name": "powershell.exe",
"process.parent.entity_id": "A",
},
"id": "B",
"name": "mimikatz.exe",
"name": "powershell.exe",
"parent": "A",
"stats": Object {
"byCategory": Object {},
@ -88,11 +88,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "C",
"process.name": "notepad.exe",
"process.name": "iexlorer.exe",
"process.parent.entity_id": "A",
},
"id": "C",
"name": "notepad.exe",
"name": "iexlorer.exe",
"parent": "A",
"stats": Object {
"byCategory": Object {},
@ -103,11 +103,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "I",
"process.name": "mimikatz.exe",
"process.name": "explorer.exe",
"process.parent.entity_id": "A",
},
"id": "I",
"name": "mimikatz.exe",
"name": "explorer.exe",
"parent": "A",
"stats": Object {
"byCategory": Object {},
@ -118,11 +118,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "D",
"process.name": "powershell.exe",
"process.name": "mimikatz.exe",
"process.parent.entity_id": "B",
},
"id": "D",
"name": "powershell.exe",
"name": "mimikatz.exe",
"parent": "B",
"stats": Object {
"byCategory": Object {},
@ -148,11 +148,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "F",
"process.name": "iexlorer.exe",
"process.name": "explorer.exe",
"process.parent.entity_id": "C",
},
"id": "F",
"name": "iexlorer.exe",
"name": "explorer.exe",
"parent": "C",
"stats": Object {
"byCategory": Object {},
@ -163,11 +163,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "G",
"process.name": "iexlorer.exe",
"process.name": "powershell.exe",
"process.parent.entity_id": "C",
},
"id": "G",
"name": "iexlorer.exe",
"name": "powershell.exe",
"parent": "C",
"stats": Object {
"byCategory": Object {},
@ -178,11 +178,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "H",
"process.name": "iexlorer.exe",
"process.name": "lsass.exe",
"process.parent.entity_id": "G",
},
"id": "H",
"name": "iexlorer.exe",
"name": "lsass.exe",
"parent": "G",
"stats": Object {
"byCategory": Object {},
@ -439,11 +439,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "A",
"process.name": "notepad.exe",
"process.name": "lsass.exe",
"process.parent.entity_id": "",
},
"id": "A",
"name": "notepad.exe",
"name": "lsass.exe",
"parent": undefined,
"stats": Object {
"byCategory": Object {},
@ -457,11 +457,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "B",
"process.name": "mimikatz.exe",
"process.name": "powershell.exe",
"process.parent.entity_id": "A",
},
"id": "B",
"name": "mimikatz.exe",
"name": "powershell.exe",
"parent": "A",
"stats": Object {
"byCategory": Object {},
@ -475,11 +475,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "C",
"process.name": "notepad.exe",
"process.name": "iexlorer.exe",
"process.parent.entity_id": "A",
},
"id": "C",
"name": "notepad.exe",
"name": "iexlorer.exe",
"parent": "A",
"stats": Object {
"byCategory": Object {},
@ -493,11 +493,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "I",
"process.name": "mimikatz.exe",
"process.name": "explorer.exe",
"process.parent.entity_id": "A",
},
"id": "I",
"name": "mimikatz.exe",
"name": "explorer.exe",
"parent": "A",
"stats": Object {
"byCategory": Object {},
@ -511,11 +511,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "D",
"process.name": "powershell.exe",
"process.name": "mimikatz.exe",
"process.parent.entity_id": "B",
},
"id": "D",
"name": "powershell.exe",
"name": "mimikatz.exe",
"parent": "B",
"stats": Object {
"byCategory": Object {},
@ -547,11 +547,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "F",
"process.name": "iexlorer.exe",
"process.name": "explorer.exe",
"process.parent.entity_id": "C",
},
"id": "F",
"name": "iexlorer.exe",
"name": "explorer.exe",
"parent": "C",
"stats": Object {
"byCategory": Object {},
@ -565,11 +565,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "G",
"process.name": "iexlorer.exe",
"process.name": "powershell.exe",
"process.parent.entity_id": "C",
},
"id": "G",
"name": "iexlorer.exe",
"name": "powershell.exe",
"parent": "C",
"stats": Object {
"byCategory": Object {},
@ -583,11 +583,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "H",
"process.name": "iexlorer.exe",
"process.name": "lsass.exe",
"process.parent.entity_id": "G",
},
"id": "H",
"name": "iexlorer.exe",
"name": "lsass.exe",
"parent": "G",
"stats": Object {
"byCategory": Object {},
@ -608,11 +608,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "A",
"process.name": "powershell.exe",
"process.name": "explorer.exe",
"process.parent.entity_id": "",
},
"id": "A",
"name": "powershell.exe",
"name": "explorer.exe",
"parent": undefined,
"stats": Object {
"byCategory": Object {},
@ -623,11 +623,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "B",
"process.name": "powershell.exe",
"process.name": "iexlorer.exe",
"process.parent.entity_id": "A",
},
"id": "B",
"name": "powershell.exe",
"name": "iexlorer.exe",
"parent": "A",
"stats": Object {
"byCategory": Object {},
@ -661,11 +661,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "A",
"process.name": "powershell.exe",
"process.name": "explorer.exe",
"process.parent.entity_id": "",
},
"id": "A",
"name": "powershell.exe",
"name": "explorer.exe",
"parent": undefined,
"stats": Object {
"byCategory": Object {},
@ -679,11 +679,11 @@ Object {
"data": Object {
"@timestamp": 1606234833273,
"process.entity_id": "B",
"process.name": "powershell.exe",
"process.name": "iexlorer.exe",
"process.parent.entity_id": "A",
},
"id": "B",
"name": "powershell.exe",
"name": "iexlorer.exe",
"parent": "A",
"stats": Object {
"byCategory": Object {},

View file

@ -22,7 +22,9 @@ describe('Pagination', () => {
};
describe('cursor', () => {
const root = generator.generateEvent();
const events = Array.from(generator.relatedEventsGenerator({ node: root, relatedEvents: 5 }));
const events = Array.from(
generator.relatedEventsGenerator({ node: root, relatedEvents: 5, sessionEntryLeader: 'test' })
);
it('does build a cursor when received the same number of events as was requested', () => {
expect(PaginationBuilder.buildCursorRequestLimit(4, events)).not.toBeNull();