[Security Solution] [Analyzer] Use more correct ids from alerts for entity request, clean up some tests (#137370) (#137894)

* Use more correct ids from alerts for entity request, clean up some tests

* Fix cypress tests

* Remove cypress config change

* Update failing cypress tests, address pr comment

* Address pr comment in reality

* Update cypress data to work with analyzer api

* Update alert count in rule tests

* Delete commented code

(cherry picked from commit 2a4c473fdb)

Co-authored-by: Kevin Qualters <56408403+kqualters-elastic@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2022-08-03 10:09:20 -04:00 committed by GitHub
parent c01a9c9609
commit 6fb0959791
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 348 additions and 121 deletions

View file

@ -11,10 +11,14 @@ import {
SUMMARY_VIEW_INVESTIGATE_IN_TIMELINE_BUTTON,
INSIGHTS_RELATED_ALERTS_BY_SESSION,
INSIGHTS_INVESTIGATE_IN_TIMELINE_BUTTON,
INSIGHTS_RELATED_ALERTS_BY_ANCESTRY,
INSIGHTS_INVESTIGATE_ANCESTRY_ALERTS_IN_TIMELINE_BUTTON,
} from '../../screens/alerts_details';
import { QUERY_TAB_BUTTON, TIMELINE_TITLE } from '../../screens/timeline';
import { expandFirstAlert } from '../../tasks/alerts';
import { verifyInsightCount } from '../../tasks/alerts_details';
import { setStartDate } from '../../tasks/date_picker';
import { closeTimeline } from '../../tasks/timeline';
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
import { cleanKibana } from '../../tasks/common';
@ -31,6 +35,8 @@ describe('Alert Flyout', () => {
login();
createCustomRuleEnabled(getNewRule(), 'rule1');
visitWithoutDateRange(ALERTS_URL);
const dateContainingAllEvents = 'Jul 27, 2015 @ 00:00:00.000';
setStartDate(dateContainingAllEvents);
waitForAlertsToPopulate();
expandFirstAlert();
});
@ -56,25 +62,16 @@ describe('Alert Flyout', () => {
});
it('Opens a new timeline investigation (from an insights module)', () => {
cy.get(INSIGHTS_RELATED_ALERTS_BY_SESSION)
.click()
.invoke('text')
.then((relatedAlertsBySessionText) => {
// Extract the count from the text
const alertCount = relatedAlertsBySessionText.match(/(\d)/);
const actualCount = alertCount && alertCount[0];
verifyInsightCount({
tableSelector: INSIGHTS_RELATED_ALERTS_BY_SESSION,
investigateSelector: INSIGHTS_INVESTIGATE_IN_TIMELINE_BUTTON,
});
});
// Make sure we can see the table
cy.contains('New Rule Test').should('be.visible');
// Click on the first button that lets us investigate in timeline
cy.get(ALERT_FLYOUT).find(INSIGHTS_INVESTIGATE_IN_TIMELINE_BUTTON).click();
// Make sure a new timeline is created and opened
cy.get(TIMELINE_TITLE).should('contain.text', 'Untitled timeline');
// The alert count in this timeline should match the count shown on the alert flyout
cy.get(QUERY_TAB_BUTTON).should('contain.text', actualCount);
});
it('Opens a new timeline investigation with alert ids from the process ancestry', () => {
verifyInsightCount({
tableSelector: INSIGHTS_RELATED_ALERTS_BY_ANCESTRY,
investigateSelector: INSIGHTS_INVESTIGATE_ANCESTRY_ALERTS_IN_TIMELINE_BUTTON,
});
});
});

View file

@ -72,7 +72,7 @@ describe('EQL rules', () => {
const expectedTags = getEqlRule().tags.join('');
const expectedMitre = formatMitreAttackDescription(getEqlRule().mitre);
const expectedNumberOfRules = 1;
const expectedNumberOfAlerts = '1 alert';
const expectedNumberOfAlerts = '2 alerts';
beforeEach(() => {
createTimeline(getEqlRule().timeline).then((response) => {

View file

@ -77,3 +77,7 @@ export const SUMMARY_VIEW_INVESTIGATE_IN_TIMELINE_BUTTON = `${SUMMARY_VIEW} [ari
export const INSIGHTS_RELATED_ALERTS_BY_SESSION = `[data-test-subj='related-alerts-by-session']`;
export const INSIGHTS_INVESTIGATE_IN_TIMELINE_BUTTON = `${INSIGHTS_RELATED_ALERTS_BY_SESSION} [aria-label='Investigate in timeline']`;
export const INSIGHTS_RELATED_ALERTS_BY_ANCESTRY = `[data-test-subj='related-alerts-by-ancestry']`;
export const INSIGHTS_INVESTIGATE_ANCESTRY_ALERTS_IN_TIMELINE_BUTTON = `[data-test-subj='investigate-ancestry-in-timeline']`;

View file

@ -24,5 +24,14 @@ export const DATE_PICKER_END_DATE_POPOVER_BUTTON_TIMELINE =
export const DATE_PICKER_START_DATE_POPOVER_BUTTON =
'div[data-test-subj="globalDatePicker"] button[data-test-subj="superDatePickerstartDatePopoverButton"]';
export const GLOBAL_FILTERS_CONTAINER = '[data-test-subj="globalDatePicker"]';
export const SHOW_DATES_BUTTON = '[data-test-subj="superDatePickerShowDatesButton"]';
export const DATE_PICKER_SHOW_DATE_POPOVER_BUTTON = `${GLOBAL_FILTERS_CONTAINER} ${SHOW_DATES_BUTTON}`;
export const DATE_PICKER_RELATIVE_DATE_INPUT_UNIT_SELECTOR =
'[data-test-subj="superDatePickerRelativeDateInputUnitSelector"]';
export const DATE_PICKER_START_DATE_POPOVER_BUTTON_TIMELINE =
'[data-test-subj="timeline-date-picker-container"] [data-test-subj="superDatePickerstartDatePopoverButton"]';

View file

@ -6,12 +6,14 @@
*/
import {
ALERT_FLYOUT,
ENRICHMENT_COUNT_NOTIFICATION,
JSON_VIEW_TAB,
OVERVIEW_TAB,
TABLE_TAB,
FILTER_INPUT,
} from '../screens/alerts_details';
import { TIMELINE_TITLE, QUERY_TAB_BUTTON } from '../screens/timeline';
export const filterBy = (value: string) => {
cy.get(FILTER_INPUT).type(value);
@ -32,3 +34,35 @@ export const openTable = () => {
export const openThreatIndicatorDetails = () => {
cy.get(ENRICHMENT_COUNT_NOTIFICATION).click();
};
export const verifyInsightCount = ({
tableSelector,
investigateSelector,
}: {
tableSelector: string;
investigateSelector: string;
}) => {
cy.get(tableSelector).click();
// Make sure the table containing data has loaded before parsing the text for the alert count
cy.get(investigateSelector);
cy.get(tableSelector)
.invoke('text')
.then((relatedAlertsByAncestryText) => {
// Extract the count from the text
const alertCount = relatedAlertsByAncestryText.match(/(\d)/);
const actualCount = alertCount && alertCount[0];
// Make sure we can see the table
cy.contains('New Rule Test').should('be.visible');
// Click on the first button that lets us investigate in timeline
cy.get(ALERT_FLYOUT).find(investigateSelector).click();
// Make sure a new timeline is created and opened
cy.get(TIMELINE_TITLE).should('contain.text', 'Untitled timeline');
// The alert count in this timeline should match the count shown on the alert flyout
cy.get(QUERY_TAB_BUTTON).should('contain.text', actualCount);
});
};

View file

@ -13,7 +13,10 @@ import {
DATE_PICKER_END_DATE_POPOVER_BUTTON,
DATE_PICKER_END_DATE_POPOVER_BUTTON_TIMELINE,
DATE_PICKER_START_DATE_POPOVER_BUTTON,
GLOBAL_FILTERS_CONTAINER,
SHOW_DATES_BUTTON,
DATE_PICKER_START_DATE_POPOVER_BUTTON_TIMELINE,
DATE_PICKER_SHOW_DATE_POPOVER_BUTTON,
} from '../screens/date_picker';
export const setEndDate = (date: string) => {
@ -25,11 +28,21 @@ export const setEndDate = (date: string) => {
};
export const setStartDate = (date: string) => {
cy.get(DATE_PICKER_START_DATE_POPOVER_BUTTON).click({ force: true });
cy.get(GLOBAL_FILTERS_CONTAINER);
cy.get('.euiSuperDatePicker');
cy.get('body').then(($container) => {
if ($container.find(SHOW_DATES_BUTTON).length > 0) {
cy.get(DATE_PICKER_SHOW_DATE_POPOVER_BUTTON).click({ force: true });
} else {
cy.get(DATE_PICKER_START_DATE_POPOVER_BUTTON).click({ force: true });
}
});
cy.get(DATE_PICKER_ABSOLUTE_TAB).first().click({ force: true });
cy.get(DATE_PICKER_ABSOLUTE_INPUT).click().clear().type(date);
cy.get(DATE_PICKER_APPLY_BUTTON).click();
};
export const setTimelineEndDate = (date: string) => {

View file

@ -37,6 +37,14 @@ export const Insights = React.memo<Props>(
'insightsRelatedAlertsByProcessAncestry'
);
const processEntityField = find({ category: 'process', field: 'process.entity_id' }, data);
const originalDocumentId = find(
{ category: 'kibana', field: 'kibana.alert.ancestors.id' },
data
);
const originalDocumentIndex = find(
{ category: 'kibana', field: 'kibana.alert.rule.parameters.index' },
data
);
const hasProcessEntityInfo =
isRelatedAlertsByProcessAncestryEnabled && processEntityField && processEntityField.values;
@ -64,6 +72,13 @@ export const Insights = React.memo<Props>(
hasSourceEventInfo ||
hasProcessSessionInfo;
const canShowAncestryInsight =
isRelatedAlertsByProcessAncestryEnabled &&
processEntityField &&
processEntityField.values &&
originalDocumentId &&
originalDocumentIndex;
// If we're in read-only mode or don't have any insight-related data,
// don't render anything.
if (isReadOnly || !canShowAtLeastOneInsight) {
@ -107,17 +122,17 @@ export const Insights = React.memo<Props>(
</EuiFlexItem>
)}
{isRelatedAlertsByProcessAncestryEnabled &&
processEntityField &&
processEntityField.values && (
<EuiFlexItem>
<RelatedAlertsByProcessAncestry
data={processEntityField}
eventId={eventId}
timelineId={timelineId}
/>
</EuiFlexItem>
)}
{canShowAncestryInsight && (
<EuiFlexItem data-test-subj="related-alerts-by-ancestry">
<RelatedAlertsByProcessAncestry
data={processEntityField}
originalDocumentId={originalDocumentId}
index={originalDocumentIndex}
eventId={eventId}
timelineId={timelineId}
/>
</EuiFlexItem>
)}
</EuiFlexGroup>
</div>
);

View file

@ -21,6 +21,24 @@ jest.mock('../../../containers/alerts/use_alert_prevalence_from_process_tree', (
}));
const mockUseAlertPrevalenceFromProcessTree = useAlertPrevalenceFromProcessTree as jest.Mock;
const props = {
eventId: 'random',
data: {
field: 'testfield',
values: ['test value'],
isObjectArray: false,
},
index: {
field: 'index',
values: ['test value'],
isObjectArray: false,
},
originalDocumentId: {
field: '_id',
values: ['original'],
isObjectArray: false,
},
};
describe('RelatedAlertsByProcessAncestry', () => {
beforeEach(() => {
jest.resetAllMocks();
@ -29,14 +47,7 @@ describe('RelatedAlertsByProcessAncestry', () => {
it('shows an accordion and does not fetch data right away', () => {
render(
<TestProviders>
<RelatedAlertsByProcessAncestry
eventId="random"
data={{
field: 'testfield',
values: ['test value'],
isObjectArray: false,
}}
/>
<RelatedAlertsByProcessAncestry {...props} />
</TestProviders>
);
@ -51,14 +62,7 @@ describe('RelatedAlertsByProcessAncestry', () => {
render(
<TestProviders>
<RelatedAlertsByProcessAncestry
eventId="random"
data={{
field: 'testfield',
values: ['test value'],
isObjectArray: false,
}}
/>
<RelatedAlertsByProcessAncestry {...props} />
</TestProviders>
);
@ -75,14 +79,7 @@ describe('RelatedAlertsByProcessAncestry', () => {
render(
<TestProviders>
<RelatedAlertsByProcessAncestry
eventId="random"
data={{
field: 'testfield',
values: ['test value'],
isObjectArray: false,
}}
/>
<RelatedAlertsByProcessAncestry {...props} />
</TestProviders>
);
@ -100,14 +97,7 @@ describe('RelatedAlertsByProcessAncestry', () => {
render(
<TestProviders>
<RelatedAlertsByProcessAncestry
eventId="random"
data={{
field: 'testfield',
values: ['test value'],
isObjectArray: false,
}}
/>
<RelatedAlertsByProcessAncestry {...props} />
</TestProviders>
);

View file

@ -9,6 +9,7 @@ import React, { useMemo, useCallback, useEffect, useState } from 'react';
import { EuiSpacer, EuiLoadingSpinner } from '@elastic/eui';
import type { DataProvider } from '../../../../../common/types';
import { TimelineId } from '../../../../../common/types/timeline';
import type { TimelineEventsDetailsItem } from '../../../../../common/search_strategy/timeline';
import { getDataProvider } from '../table/use_action_cell_data_provider';
import { useAlertPrevalenceFromProcessTree } from '../../../containers/alerts/use_alert_prevalence_from_process_tree';
@ -21,6 +22,8 @@ import { PROCESS_ANCESTRY, PROCESS_ANCESTRY_COUNT, PROCESS_ANCESTRY_ERROR } from
interface Props {
data: TimelineEventsDetailsItem;
eventId: string;
index: TimelineEventsDetailsItem;
originalDocumentId: TimelineEventsDetailsItem;
timelineId?: string;
}
@ -56,53 +59,57 @@ interface Cache {
* Due to the ephemeral nature of the data, it was decided to keep the
* state inside the component rather than to add it to Redux.
*/
export const RelatedAlertsByProcessAncestry = React.memo<Props>(({ data, eventId, timelineId }) => {
const [showContent, setShowContent] = useState(false);
const [cache, setCache] = useState<Partial<Cache>>({});
export const RelatedAlertsByProcessAncestry = React.memo<Props>(
({ data, originalDocumentId, index, eventId, timelineId }) => {
const [showContent, setShowContent] = useState(false);
const [cache, setCache] = useState<Partial<Cache>>({});
const onToggle = useCallback((isOpen: boolean) => setShowContent(isOpen), []);
const onToggle = useCallback((isOpen: boolean) => setShowContent(isOpen), []);
// Makes sure the component is not fetching data before the accordion
// has been openend.
const renderContent = useCallback(() => {
if (!showContent) {
return null;
} else if (cache.alertIds) {
// Makes sure the component is not fetching data before the accordion
// has been openend.
const renderContent = useCallback(() => {
if (!showContent) {
return null;
} else if (cache.alertIds) {
return (
<ActualRelatedAlertsByProcessAncestry
eventId={eventId}
timelineId={timelineId}
alertIds={cache.alertIds}
/>
);
}
return (
<ActualRelatedAlertsByProcessAncestry
<FetchAndNotifyCachedAlertsByProcessAncestry
data={data}
index={index}
originalDocumentId={originalDocumentId}
eventId={eventId}
timelineId={timelineId}
alertIds={cache.alertIds}
onCacheLoad={setCache}
/>
);
}
}, [showContent, cache, data, eventId, timelineId, index, originalDocumentId]);
const isEmpty = !!cache.alertIds && cache.alertIds.length === 0;
return (
<FetchAndNotifyCachedAlertsByProcessAncestry
data={data}
eventId={eventId}
timelineId={timelineId}
onCacheLoad={setCache}
<InsightAccordion
prefix="RelatedAlertsByProcessAncestry"
// `renderContent` and the associated sub-components are making sure to
// render the correct loading and error states so we can omit these states here
state={isEmpty ? 'empty' : 'success'}
text={
// If we have fetched the alerts, display the count here, otherwise omit the count
cache.alertIds ? PROCESS_ANCESTRY_COUNT(cache.alertIds.length) : PROCESS_ANCESTRY
}
renderContent={renderContent}
onToggle={onToggle}
/>
);
}, [showContent, cache, data, eventId, timelineId]);
const isEmpty = !!cache.alertIds && cache.alertIds.length === 0;
return (
<InsightAccordion
prefix="RelatedAlertsByProcessAncestry"
// `renderContent` and the associated sub-components are making sure to
// render the correct loading and error states so we can omit these states here
state={isEmpty ? 'empty' : 'success'}
text={
// If we have fetched the alerts, display the count here, otherwise omit the count
cache.alertIds ? PROCESS_ANCESTRY_COUNT(cache.alertIds.length) : PROCESS_ANCESTRY
}
renderContent={renderContent}
onToggle={onToggle}
/>
);
});
}
);
RelatedAlertsByProcessAncestry.displayName = 'RelatedAlertsByProcessAncestry';
@ -112,10 +119,22 @@ RelatedAlertsByProcessAncestry.displayName = 'RelatedAlertsByProcessAncestry';
const FetchAndNotifyCachedAlertsByProcessAncestry: React.FC<{
data: TimelineEventsDetailsItem;
eventId: string;
index: TimelineEventsDetailsItem;
originalDocumentId: TimelineEventsDetailsItem;
timelineId?: string;
onCacheLoad: (cache: Cache) => void;
}> = ({ data, timelineId, onCacheLoad, eventId }) => {
const { loading, error, alertIds } = useAlertPrevalenceFromProcessTree(eventId, timelineId);
}> = ({ data, originalDocumentId, index, timelineId, onCacheLoad, eventId }) => {
const { values: wrappedProcessEntityId } = data;
const { values: indices } = index;
const { values: wrappedDocumentId } = originalDocumentId;
const documentId = Array.isArray(wrappedDocumentId) ? wrappedDocumentId[0] : '';
const processEntityId = Array.isArray(wrappedProcessEntityId) ? wrappedProcessEntityId[0] : '';
const { loading, error, alertIds } = useAlertPrevalenceFromProcessTree({
processEntityId,
timelineId: timelineId ?? TimelineId.active,
documentId,
indices: indices ?? [],
});
useEffect(() => {
if (alertIds) {
@ -162,7 +181,11 @@ const ActualRelatedAlertsByProcessAncestry: React.FC<{
<>
<SimpleAlertTable alertIds={alertIds} />
<EuiSpacer />
<InvestigateInTimelineButton asEmptyButton={false} dataProviders={dataProviders}>
<InvestigateInTimelineButton
asEmptyButton={false}
dataProviders={dataProviders}
data-test-subj={'investigate-ancestry-in-timeline'}
>
{ACTION_INVESTIGATE_IN_TIMELINE}
</InvestigateInTimelineButton>
</>

View file

@ -21,7 +21,7 @@ import { ACTION_INVESTIGATE_IN_TIMELINE } from '../../../../detections/component
export const InvestigateInTimelineButton: React.FunctionComponent<{
asEmptyButton: boolean;
dataProviders: DataProvider[];
}> = ({ asEmptyButton, children, dataProviders }) => {
}> = ({ asEmptyButton, children, dataProviders, ...rest }) => {
const dispatch = useDispatch();
const clearTimeline = useCreateTimeline({
@ -64,7 +64,11 @@ export const InvestigateInTimelineButton: React.FunctionComponent<{
{children}
</EuiButtonEmpty>
) : (
<EuiButton aria-label={ACTION_INVESTIGATE_IN_TIMELINE} onClick={configureAndOpenTimeline}>
<EuiButton
aria-label={ACTION_INVESTIGATE_IN_TIMELINE}
onClick={configureAndOpenTimeline}
{...rest}
>
{children}
</EuiButton>
);

View file

@ -27,6 +27,18 @@ interface EntityResponse {
schema: object;
}
interface UseAlertPrevalenceFromProcessTree {
processEntityId: string;
documentId: string;
timelineId: string;
indices: string[];
}
interface UseAlertDocumentAnalyzerSchema {
documentId: string;
indices: string[];
}
interface TreeResponse {
statsNodes: Array<{
data: object;
@ -42,12 +54,12 @@ interface TreeResponse {
alertIds: string[];
}
function useAlertDocumentAnalyzerSchema(processEntityId: string, indices: string[]) {
function useAlertDocumentAnalyzerSchema({ documentId, indices }: UseAlertDocumentAnalyzerSchema) {
const http = useHttp();
const query = useQuery<EntityResponse[]>(['getAlertPrevalenceSchema', processEntityId], () => {
const query = useQuery<EntityResponse[]>(['getAlertPrevalenceSchema', documentId], () => {
return http.get<EntityResponse[]>(`/api/endpoint/resolver/entity`, {
query: {
_id: processEntityId,
_id: documentId,
indices,
},
});
@ -59,7 +71,7 @@ function useAlertDocumentAnalyzerSchema(processEntityId: string, indices: string
id: null,
schema: null,
};
} else if (query.data) {
} else if (query.data && query.data.length > 0) {
const {
data: [{ schema, id }],
} = query;
@ -79,15 +91,20 @@ function useAlertDocumentAnalyzerSchema(processEntityId: string, indices: string
}
}
export function useAlertPrevalenceFromProcessTree(
processEntityId: string,
timelineId: string | undefined
): UserAlertPrevalenceFromProcessTreeResult {
export function useAlertPrevalenceFromProcessTree({
processEntityId,
documentId,
timelineId,
indices,
}: UseAlertPrevalenceFromProcessTree): UserAlertPrevalenceFromProcessTreeResult {
const http = useHttp();
const { selectedPatterns, to, from } = useTimelineDataFilters(timelineId);
const { loading, id, schema } = useAlertDocumentAnalyzerSchema(processEntityId, selectedPatterns);
const alertAndOriginalIndices = [...new Set(selectedPatterns.concat(indices))];
const { loading, id, schema } = useAlertDocumentAnalyzerSchema({
documentId,
indices: alertAndOriginalIndices,
});
const query = useQuery<ProcessTreeAlertPrevalenceResponse>(
['getAlertPrevalenceFromProcessTree', id],
() => {
@ -96,7 +113,7 @@ export function useAlertPrevalenceFromProcessTree(
schema,
ancestors: 200,
descendants: 500,
indexPatterns: selectedPatterns,
indexPatterns: alertAndOriginalIndices,
nodes: [id],
timeRange: { from, to },
includeHits: true,

View file

@ -7,7 +7,6 @@
import type { IScopedClusterClient } from '@kbn/core/server';
import type { AlertsClient } from '@kbn/rule-registry-plugin/server';
import { ALERT_RULE_UUID } from '@kbn/rule-data-utils';
import type { JsonObject } from '@kbn/utility-types';
import type { EventStats, ResolverSchema } from '../../../../../../common/endpoint/types';
import type { NodeID, TimeRange } from '../utils';
@ -197,9 +196,7 @@ export class StatsQuery {
},
])
);
const alertIdsRaw: Array<string | undefined> = alertsBody.hits.hits.map((hit) => {
return hit._source && hit._source[ALERT_RULE_UUID];
});
const alertIdsRaw: Array<string | undefined> = alertsBody.hits.hits.map((hit) => hit._id);
const alertIds = alertIdsRaw.flatMap((id) => (!id ? [] : [id]));
const eventAggStats = [...eventsWithAggs.values()];

View file

@ -51,6 +51,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
`--xpack.securitySolution.enableExperimental=${JSON.stringify([
'riskyHostsEnabled',
'riskyUsersEnabled',
'insightsRelatedAlertsByProcessAncestry',
])}`,
`--home.disableWelcomeScreen=true`,
],

View file

@ -120,3 +120,126 @@
}
}
}
{
"type": "doc",
"value": {
"id": "_aZE5nwBOpWiDweSth_E",
"index": "auditbeat-2022",
"source": {
"@timestamp" : "2022-03-04T19:41:34.045Z",
"host" : {
"hostname" : "test.local",
"architecture" : "x86_64",
"os" : {
"platform" : "darwin",
"version" : "10.16",
"family" : "darwin",
"name" : "Mac OS X",
"kernel" : "21.3.0",
"build" : "21D62",
"type" : "macos"
},
"id" : "44426D67-79AB-547C-7777-440AB8F5DDD2",
"ip" : [
"fe80::bade:48ff:fe00:1122",
"fe81::4ab:9565:1199:be3",
"192.168.5.175",
"fe80::40d7:d0ff:fe66:f55",
"fe81::40d8:d0ff:fe66:f55",
"fe82::c2c:6bdf:3307:dce0",
"fe83::5069:fcd5:e31c:7059",
"fe80::ce81:b2c:bd2c:69e",
"fe80::febc:bbc1:c517:827b",
"fe80::6d09:bee6:55a5:539d",
"fe80::c920:752e:1e0e:edc9",
"fe80::a4a:ca38:761f:83e2"
],
"mac" : [
"ad:df:48:00:11:22",
"a6:86:e7:ae:5a:b6",
"a9:83:e7:ae:5a:b6",
"43:d8:d0:66:0f:55",
"42:d8:d0:66:0f:57",
"82:70:c7:c2:3c:01",
"82:70:c6:c2:4c:00",
"82:76:a6:c2:3c:05",
"82:70:c6:b2:3c:04",
"82:71:a6:c2:3c:01"
],
"name" : "siem-kibana"
},
"agent" : {
"type" : "winlogbeat",
"version" : "8.1.0",
"ephemeral_id" : "f6df090f-656a-4a79-a6a1-0c8671c9752d",
"id" : "0ebd469b-c164-4734-00e6-96d018098dc7",
"name" : "test.local"
},
"event" : {
"module" : "sysmon",
"dataset" : "process",
"kind" : "event",
"category" : [
"process"
],
"type" : [
"start"
],
"action" : "process_started"
},
"destination": {
"port": 80
},
"process" : {
"start" : "2022-03-04T19:41:34.902Z",
"pid" : 30884,
"working_directory" : "/Users/test/security_solution",
"hash" : {
"sha1" : "ae2d46c38fa207efbea5fcecd6294eebbf5af00f"
},
"parent" : {
"pid" : 777
},
"executable" : "/bin/zsh",
"name" : "zsh",
"args" : [
"-zsh"
],
"entity_id" : "q6pltOhTWlQx3BCE",
"entry_leader": {
"entity_id": "q6pltOhTWlQx3BCE",
"name": "fake entry",
"pid": 2342342
}
},
"message" : "Process zsh (PID: 27884) by user test STARTED",
"user" : {
"id" : "505",
"group" : {
"name" : "staff",
"id" : "20"
},
"effective" : {
"id" : "505",
"group" : {
"id" : "20"
}
},
"saved" : {
"id" : "505",
"group" : {
"id" : "20"
}
},
"name" : "test"
},
"service" : {
"type" : "system"
},
"ecs" : {
"version" : "8.0.0"
}
}
}
}