mirror of
https://github.com/elastic/kibana.git
synced 2025-06-28 11:05:39 -04:00
[Security Solution][Endpoint Exceptions] Fixes bug where behavior alerts do not show nested code signatures with subject name and trusted field (#212325)
## Summary When navigating to the endpoint exceptions form from an alert, we pre-populate certain exceptions fields based on the type of alert. There was a bug for behavior alerts where we did not use the proper nested `code_signature` field for windows and mac endpoints. Instead of showing the nested `code_signature` field that has the `subject_name` and `trusted` sub-fields, we only showed non-nested `code_signature subject field. This PR also refactors the code to account for the following behaviors that we want: - [x] If `field.Ext.code_signature` is present, we want to use the nested `code_signature` subject field with the `subject_name` and `trusted` sub-fields for - [x] If `field.Ext.code_signature` is not present, we will default to the non-nested `field.code_signature.subject_name` and `field.code_signature.trusted` field pair. - [x] We will only show non-empty pre-populated values and also only code signature values with the `trusted` field set to `true` - [x] Pre-populated code signature fields are only present in windows and mac OSes. - [x] Behavior, ransomware and default alerts had the code_signature adjustments - [x] Previously the code duplicated a set of the pre-populated fields PER code signature. Now, each pre-populated field is only shown once, followed by all valid code_signatures. - [x] Does not allow duplicate code signatures # SCREENSHOTS Behavior alert w/ nested `process.Ext.code_signature` and non-nested `dll.code_signature` fields  Malware alert w/ nested `file.Ext.code_signature` <img width="1281" alt="image" src="https://github.com/user-attachments/assets/4845c6e5-5567-49df-b66a-1b9a2e6410db" /> --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
8d50c08a43
commit
76e256ccff
6 changed files with 1036 additions and 315 deletions
|
@ -7,10 +7,11 @@
|
||||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { CodeSignature } from '../file';
|
import type { CodeSignature, Ext } from '../file';
|
||||||
import type { ProcessPe } from '../process';
|
import type { ProcessPe } from '../process';
|
||||||
|
|
||||||
export interface DllEcs {
|
export interface DllEcs {
|
||||||
|
Ext?: Ext;
|
||||||
path?: string;
|
path?: string;
|
||||||
code_signature?: CodeSignature;
|
code_signature?: CodeSignature;
|
||||||
pe?: ProcessPe;
|
pe?: ProcessPe;
|
||||||
|
|
|
@ -14,7 +14,7 @@ interface Original {
|
||||||
|
|
||||||
export interface CodeSignature {
|
export interface CodeSignature {
|
||||||
subject_name: string[];
|
subject_name: string[];
|
||||||
trusted: string[];
|
trusted: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Token {
|
export interface Token {
|
||||||
|
@ -72,6 +72,8 @@ export interface FileEcs {
|
||||||
|
|
||||||
type?: string[];
|
type?: string[];
|
||||||
|
|
||||||
|
code_signature?: CodeSignature;
|
||||||
|
|
||||||
device?: string[];
|
device?: string[];
|
||||||
|
|
||||||
inode?: string[];
|
inode?: string[];
|
||||||
|
|
|
@ -529,6 +529,10 @@ export class EndpointDocGenerator extends BaseDataGenerator {
|
||||||
trusted: false,
|
trusted: false,
|
||||||
subject_name: 'bad signer',
|
subject_name: 'bad signer',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
trusted: true,
|
||||||
|
subject_name: 'a good signer',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
malware_classification: {
|
malware_classification: {
|
||||||
identifier: 'endpointpe',
|
identifier: 'endpointpe',
|
||||||
|
@ -900,6 +904,10 @@ export class EndpointDocGenerator extends BaseDataGenerator {
|
||||||
trusted: false,
|
trusted: false,
|
||||||
subject_name: 'bad signer',
|
subject_name: 'bad signer',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
trusted: true,
|
||||||
|
subject_name: 'good signer',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
user: 'SYSTEM',
|
user: 'SYSTEM',
|
||||||
token: {
|
token: {
|
||||||
|
@ -921,8 +929,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
|
||||||
* Returns the default DLLs used in alerts
|
* Returns the default DLLs used in alerts
|
||||||
*/
|
*/
|
||||||
private getAlertsDefaultDll() {
|
private getAlertsDefaultDll() {
|
||||||
return [
|
return {
|
||||||
{
|
|
||||||
pe: {
|
pe: {
|
||||||
architecture: 'x64',
|
architecture: 'x64',
|
||||||
},
|
},
|
||||||
|
@ -949,8 +956,7 @@ export class EndpointDocGenerator extends BaseDataGenerator {
|
||||||
version: '3.0.0',
|
version: '3.0.0',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -26,6 +26,7 @@ import type {
|
||||||
UpdateExceptionListItemSchema,
|
UpdateExceptionListItemSchema,
|
||||||
ExceptionListSchema,
|
ExceptionListSchema,
|
||||||
EntriesArray,
|
EntriesArray,
|
||||||
|
EntriesArrayOrUndefined,
|
||||||
} from '@kbn/securitysolution-io-ts-list-types';
|
} from '@kbn/securitysolution-io-ts-list-types';
|
||||||
import {
|
import {
|
||||||
ListOperatorTypeEnum,
|
ListOperatorTypeEnum,
|
||||||
|
@ -41,11 +42,17 @@ import type {
|
||||||
import { getNewExceptionItem, addIdToEntries } from '@kbn/securitysolution-list-utils';
|
import { getNewExceptionItem, addIdToEntries } from '@kbn/securitysolution-list-utils';
|
||||||
import { removeIdFromExceptionItemsEntries } from '@kbn/securitysolution-list-hooks';
|
import { removeIdFromExceptionItemsEntries } from '@kbn/securitysolution-list-hooks';
|
||||||
|
|
||||||
import type { EcsSecurityExtension as Ecs, CodeSignature } from '@kbn/securitysolution-ecs';
|
import type {
|
||||||
|
EcsSecurityExtension as Ecs,
|
||||||
|
CodeSignature,
|
||||||
|
FileEcs,
|
||||||
|
DllEcs,
|
||||||
|
ProcessEcs,
|
||||||
|
} from '@kbn/securitysolution-ecs';
|
||||||
import type { EventSummaryField } from '../../../common/components/event_details/types';
|
import type { EventSummaryField } from '../../../common/components/event_details/types';
|
||||||
import { getHighlightedFieldsToDisplay } from '../../../common/components/event_details/get_alert_summary_rows';
|
import { getHighlightedFieldsToDisplay } from '../../../common/components/event_details/get_alert_summary_rows';
|
||||||
import * as i18n from './translations';
|
import * as i18n from './translations';
|
||||||
import type { AlertData, Flattened } from './types';
|
import type { AlertData, Flattened, FlattenedCodeSignature } from './types';
|
||||||
|
|
||||||
import { WithCopyToClipboard } from '../../../common/lib/clipboard/with_copy_to_clipboard';
|
import { WithCopyToClipboard } from '../../../common/lib/clipboard/with_copy_to_clipboard';
|
||||||
import { ALERT_ORIGINAL_EVENT } from '../../../../common/field_maps/field_names';
|
import { ALERT_ORIGINAL_EVENT } from '../../../../common/field_maps/field_names';
|
||||||
|
@ -292,78 +299,150 @@ export const lowercaseHashValues = (
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value for `file.Ext.code_signature` which
|
* Generic function to get code signature entries from any entity
|
||||||
* can be an object or array of objects
|
|
||||||
*/
|
*/
|
||||||
export const getFileCodeSignature = (
|
export const getEntityCodeSignature = <
|
||||||
alertData: Flattened<Ecs>
|
T extends {
|
||||||
): Array<{ subjectName: string; trusted: string }> => {
|
Ext?: { code_signature?: Flattened<CodeSignature[] | CodeSignature> };
|
||||||
const { file } = alertData;
|
code_signature?: CodeSignature;
|
||||||
const codeSignature = file && file.Ext && file.Ext.code_signature;
|
}
|
||||||
|
>(
|
||||||
|
entity: Flattened<FileEcs | ProcessEcs | DllEcs> | T | undefined,
|
||||||
|
fieldPrefix: string
|
||||||
|
): EntriesArrayOrUndefined => {
|
||||||
|
if (!entity) return undefined;
|
||||||
|
|
||||||
return getCodeSignatureValue(codeSignature);
|
// Check Ext.code_signature first
|
||||||
|
if (entity.Ext?.code_signature) {
|
||||||
|
return getCodeSignatureValue(entity.Ext.code_signature, `${fieldPrefix}.Ext.code_signature`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then check direct code_signature
|
||||||
|
if (entity.code_signature?.trusted === true) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
field: `${fieldPrefix}.code_signature.subject_name`,
|
||||||
|
operator: 'included' as const,
|
||||||
|
type: 'match' as const,
|
||||||
|
value: entity.code_signature?.subject_name.toString() ?? '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: `${fieldPrefix}.code_signature.trusted`,
|
||||||
|
operator: 'included' as const,
|
||||||
|
type: 'match' as const,
|
||||||
|
value: entity.code_signature.trusted.toString(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value for `process.Ext.code_signature` which
|
* Returns an array of exception entries for either
|
||||||
* can be an object or array of objects
|
* `file.Ext.code_signature` or 'file.code_signature`
|
||||||
|
* as long as the `trusted` field is `true`.
|
||||||
*/
|
*/
|
||||||
export const getProcessCodeSignature = (
|
export const getFileCodeSignature = (alertData: Flattened<Ecs>): EntriesArrayOrUndefined =>
|
||||||
alertData: Flattened<Ecs>
|
getEntityCodeSignature(alertData.file, 'file');
|
||||||
): Array<{ subjectName: string; trusted: string }> => {
|
|
||||||
const { process } = alertData;
|
/**
|
||||||
const codeSignature = process && process.Ext && process.Ext.code_signature;
|
* Returns an array of exception entries for either
|
||||||
return getCodeSignatureValue(codeSignature);
|
* `process.Ext.code_signature` or 'process.code_signature`
|
||||||
};
|
* as long as the `trusted` field is `true`.
|
||||||
|
*/
|
||||||
|
export const getProcessCodeSignature = (alertData: Flattened<Ecs>): EntriesArrayOrUndefined =>
|
||||||
|
getEntityCodeSignature(alertData.process, 'process');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of exception entries for either
|
||||||
|
* `dll.Ext.code_signature` or 'dll.code_signature`
|
||||||
|
* as long as the `trusted` field is `true`.
|
||||||
|
*/
|
||||||
|
export const getDllCodeSignature = (alertData: Flattened<Ecs>): EntriesArrayOrUndefined =>
|
||||||
|
getEntityCodeSignature(alertData.dll, 'dll');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pre 7.10 `Ext.code_signature` fields were mistakenly populated as
|
* Pre 7.10 `Ext.code_signature` fields were mistakenly populated as
|
||||||
* a single object with subject_name and trusted.
|
* a single object with subject_name and trusted.
|
||||||
*/
|
*/
|
||||||
export const getCodeSignatureValue = (
|
export const getCodeSignatureValue = (
|
||||||
codeSignature: Flattened<CodeSignature> | Flattened<CodeSignature[]> | undefined
|
codeSignature: Flattened<CodeSignature> | FlattenedCodeSignature[] | undefined,
|
||||||
): Array<{ subjectName: string; trusted: string }> => {
|
field: string
|
||||||
|
): EntryNested[] | undefined => {
|
||||||
if (Array.isArray(codeSignature) && codeSignature.length > 0) {
|
if (Array.isArray(codeSignature) && codeSignature.length > 0) {
|
||||||
return codeSignature.map((signature) => {
|
const codeSignatureEntries: EntryNested[] = [];
|
||||||
return {
|
const noDuplicates = new Map<string, boolean>();
|
||||||
subjectName: signature?.subject_name ?? '',
|
return codeSignature.reduce((acc, signature) => {
|
||||||
trusted: signature?.trusted?.toString() ?? '',
|
if (signature?.trusted === true && !noDuplicates.has(signature?.subject_name)) {
|
||||||
};
|
noDuplicates.set(signature.subject_name, signature.trusted);
|
||||||
|
acc.push({
|
||||||
|
field,
|
||||||
|
type: 'nested',
|
||||||
|
entries: [
|
||||||
|
{
|
||||||
|
field: 'subject_name',
|
||||||
|
operator: 'included',
|
||||||
|
type: 'match',
|
||||||
|
value: signature?.subject_name ?? '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'trusted',
|
||||||
|
operator: 'included',
|
||||||
|
type: 'match',
|
||||||
|
value: signature.trusted.toString(),
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, codeSignatureEntries);
|
||||||
} else {
|
} else {
|
||||||
const signature: Flattened<CodeSignature> | undefined = !Array.isArray(codeSignature)
|
const signature: Flattened<CodeSignature> | undefined = !Array.isArray(codeSignature)
|
||||||
? codeSignature
|
? codeSignature
|
||||||
: undefined;
|
: undefined;
|
||||||
|
if (signature?.trusted === true) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
subjectName: signature?.subject_name ?? '',
|
field,
|
||||||
trusted: signature?.trusted ?? '',
|
type: 'nested',
|
||||||
|
entries: [
|
||||||
|
{
|
||||||
|
field: 'subject_name',
|
||||||
|
operator: 'included',
|
||||||
|
type: 'match',
|
||||||
|
value: signature?.subject_name ?? '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'trusted',
|
||||||
|
operator: 'included',
|
||||||
|
type: 'match',
|
||||||
|
value: signature.trusted.toString(),
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// helper type to filter empty-valued exception entries
|
|
||||||
interface ExceptionEntry {
|
|
||||||
value?: string;
|
|
||||||
entries?: ExceptionEntry[];
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes an array of Entries and filter out the ones with empty values.
|
* Takes an array of Entries and filter out the ones with empty values.
|
||||||
* It will also filter out empty values for nested entries.
|
* It will also filter out empty values for nested entries.
|
||||||
*/
|
*/
|
||||||
function filterEmptyExceptionEntries<T extends ExceptionEntry>(entries: T[]): T[] {
|
|
||||||
const finalEntries: T[] = [];
|
function filterEmptyExceptionEntries(entries: EntriesArray): EntriesArray {
|
||||||
|
const finalEntries: EntriesArray = [];
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
if (entry.entries !== undefined) {
|
if ('entries' in entry && entry.entries !== undefined) {
|
||||||
entry.entries = entry.entries.filter((el) => el.value !== undefined && el.value.length > 0);
|
entry.entries = entry.entries.filter(
|
||||||
|
(el) => 'value' in el && el.value !== undefined && el.value.length > 0
|
||||||
|
);
|
||||||
finalEntries.push(entry);
|
finalEntries.push(entry);
|
||||||
} else if (entry.value !== undefined && entry.value.length > 0) {
|
} else if ('value' in entry && entry?.value?.length > 0) {
|
||||||
finalEntries.push(entry);
|
finalEntries.push(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return finalEntries;
|
return finalEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,7 +452,6 @@ function filterEmptyExceptionEntries<T extends ExceptionEntry>(entries: T[]): T[
|
||||||
export const getPrepopulatedEndpointException = ({
|
export const getPrepopulatedEndpointException = ({
|
||||||
listId,
|
listId,
|
||||||
name,
|
name,
|
||||||
codeSignature,
|
|
||||||
eventCode,
|
eventCode,
|
||||||
listNamespace = 'agnostic',
|
listNamespace = 'agnostic',
|
||||||
alertEcsData,
|
alertEcsData,
|
||||||
|
@ -381,21 +459,16 @@ export const getPrepopulatedEndpointException = ({
|
||||||
listId: string;
|
listId: string;
|
||||||
listNamespace?: NamespaceType;
|
listNamespace?: NamespaceType;
|
||||||
name: string;
|
name: string;
|
||||||
codeSignature: { subjectName: string; trusted: string };
|
|
||||||
eventCode: string;
|
eventCode: string;
|
||||||
alertEcsData: Flattened<Ecs>;
|
alertEcsData: Flattened<Ecs>;
|
||||||
}): ExceptionsBuilderExceptionItem => {
|
}): ExceptionsBuilderExceptionItem => {
|
||||||
const { file, host } = alertEcsData;
|
const { file, host } = alertEcsData;
|
||||||
|
const fileCodeSignature = getFileCodeSignature(alertEcsData);
|
||||||
const filePath = file?.path ?? '';
|
const filePath = file?.path ?? '';
|
||||||
const sha256Hash = file?.hash?.sha256 ?? '';
|
const sha256Hash = file?.hash?.sha256 ?? '';
|
||||||
const isLinux = host?.os?.name === 'Linux';
|
const isLinux = host?.os?.name === 'Linux';
|
||||||
|
|
||||||
const commonFields: Array<{
|
const commonFields: EntriesArray = [
|
||||||
field: string;
|
|
||||||
operator: 'excluded' | 'included';
|
|
||||||
type: 'match';
|
|
||||||
value: string;
|
|
||||||
}> = [
|
|
||||||
{
|
{
|
||||||
field: isLinux ? 'file.path' : 'file.path.caseless',
|
field: isLinux ? 'file.path' : 'file.path.caseless',
|
||||||
operator: 'included',
|
operator: 'included',
|
||||||
|
@ -416,30 +489,10 @@ export const getPrepopulatedEndpointException = ({
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const entriesToAdd = () => {
|
const entriesToAdd = () => {
|
||||||
if (isLinux) {
|
if (!isLinux && fileCodeSignature !== undefined) {
|
||||||
return addIdToEntries(commonFields);
|
return addIdToEntries(filterEmptyExceptionEntries(commonFields.concat(fileCodeSignature)));
|
||||||
} else {
|
} else {
|
||||||
return addIdToEntries([
|
return addIdToEntries(filterEmptyExceptionEntries(commonFields));
|
||||||
{
|
|
||||||
field: 'file.Ext.code_signature',
|
|
||||||
type: 'nested',
|
|
||||||
entries: [
|
|
||||||
{
|
|
||||||
field: 'subject_name',
|
|
||||||
operator: 'included',
|
|
||||||
type: 'match',
|
|
||||||
value: codeSignature != null ? codeSignature.subjectName : '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'trusted',
|
|
||||||
operator: 'included',
|
|
||||||
type: 'match',
|
|
||||||
value: codeSignature != null ? codeSignature.trusted : '',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
...commonFields,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -455,7 +508,6 @@ export const getPrepopulatedEndpointException = ({
|
||||||
export const getPrepopulatedRansomwareException = ({
|
export const getPrepopulatedRansomwareException = ({
|
||||||
listId,
|
listId,
|
||||||
name,
|
name,
|
||||||
codeSignature,
|
|
||||||
eventCode,
|
eventCode,
|
||||||
listNamespace = 'agnostic',
|
listNamespace = 'agnostic',
|
||||||
alertEcsData,
|
alertEcsData,
|
||||||
|
@ -463,35 +515,17 @@ export const getPrepopulatedRansomwareException = ({
|
||||||
listId: string;
|
listId: string;
|
||||||
listNamespace?: NamespaceType;
|
listNamespace?: NamespaceType;
|
||||||
name: string;
|
name: string;
|
||||||
codeSignature: { subjectName: string; trusted: string };
|
|
||||||
eventCode: string;
|
eventCode: string;
|
||||||
alertEcsData: Flattened<Ecs>;
|
alertEcsData: Flattened<Ecs>;
|
||||||
}): ExceptionsBuilderExceptionItem => {
|
}): ExceptionsBuilderExceptionItem => {
|
||||||
const { process, Ransomware } = alertEcsData;
|
const { process, Ransomware, host } = alertEcsData;
|
||||||
|
const processCodeSignature = getProcessCodeSignature(alertEcsData);
|
||||||
const sha256Hash = process?.hash?.sha256 ?? '';
|
const sha256Hash = process?.hash?.sha256 ?? '';
|
||||||
const executable = process?.executable ?? '';
|
const executable = process?.executable ?? '';
|
||||||
const ransomwareFeature = Ransomware?.feature ?? '';
|
const ransomwareFeature = Ransomware?.feature ?? '';
|
||||||
return {
|
const isLinux = host?.os?.name === 'Linux';
|
||||||
...getNewExceptionItem({ listId, namespaceType: listNamespace, name }),
|
|
||||||
entries: addIdToEntries([
|
const commonFields: EntriesArray = [
|
||||||
{
|
|
||||||
field: 'process.Ext.code_signature',
|
|
||||||
type: 'nested',
|
|
||||||
entries: [
|
|
||||||
{
|
|
||||||
field: 'subject_name',
|
|
||||||
operator: 'included',
|
|
||||||
type: 'match',
|
|
||||||
value: codeSignature != null ? codeSignature.subjectName : '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'trusted',
|
|
||||||
operator: 'included',
|
|
||||||
type: 'match',
|
|
||||||
value: codeSignature != null ? codeSignature.trusted : '',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
field: 'process.executable',
|
field: 'process.executable',
|
||||||
operator: 'included',
|
operator: 'included',
|
||||||
|
@ -516,7 +550,19 @@ export const getPrepopulatedRansomwareException = ({
|
||||||
type: 'match',
|
type: 'match',
|
||||||
value: eventCode ?? '',
|
value: eventCode ?? '',
|
||||||
},
|
},
|
||||||
]),
|
];
|
||||||
|
|
||||||
|
const entriesToAdd = () => {
|
||||||
|
if (!isLinux && processCodeSignature !== undefined) {
|
||||||
|
return addIdToEntries(filterEmptyExceptionEntries(commonFields.concat(processCodeSignature)));
|
||||||
|
} else {
|
||||||
|
return addIdToEntries(filterEmptyExceptionEntries(commonFields));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...getNewExceptionItem({ listId, namespaceType: listNamespace, name }),
|
||||||
|
entries: entriesToAdd(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -618,6 +664,7 @@ export const getPrepopulatedMemoryShellcodeException = ({
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* eslint complexity: ["error", 21]*/
|
||||||
export const getPrepopulatedBehaviorException = ({
|
export const getPrepopulatedBehaviorException = ({
|
||||||
listId,
|
listId,
|
||||||
name,
|
name,
|
||||||
|
@ -631,8 +678,11 @@ export const getPrepopulatedBehaviorException = ({
|
||||||
eventCode: string;
|
eventCode: string;
|
||||||
alertEcsData: Flattened<Ecs>;
|
alertEcsData: Flattened<Ecs>;
|
||||||
}): ExceptionsBuilderExceptionItem => {
|
}): ExceptionsBuilderExceptionItem => {
|
||||||
const { process } = alertEcsData;
|
const { process, host } = alertEcsData;
|
||||||
const entries = filterEmptyExceptionEntries([
|
const processCodeSignature = getProcessCodeSignature(alertEcsData);
|
||||||
|
const dllCodeSignature = getDllCodeSignature(alertEcsData);
|
||||||
|
const isLinux = host?.os?.name === 'Linux';
|
||||||
|
const commonFields: EntriesArray = [
|
||||||
{
|
{
|
||||||
field: 'rule.id',
|
field: 'rule.id',
|
||||||
operator: 'included' as const,
|
operator: 'included' as const,
|
||||||
|
@ -657,12 +707,6 @@ export const getPrepopulatedBehaviorException = ({
|
||||||
type: 'match' as const,
|
type: 'match' as const,
|
||||||
value: process?.parent?.executable ?? '',
|
value: process?.parent?.executable ?? '',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
field: 'process.code_signature.subject_name',
|
|
||||||
operator: 'included' as const,
|
|
||||||
type: 'match' as const,
|
|
||||||
value: process?.code_signature?.subject_name ?? '',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
field: 'file.path',
|
field: 'file.path',
|
||||||
operator: 'included' as const,
|
operator: 'included' as const,
|
||||||
|
@ -711,12 +755,6 @@ export const getPrepopulatedBehaviorException = ({
|
||||||
type: 'match' as const,
|
type: 'match' as const,
|
||||||
value: alertEcsData.dll?.path ?? '',
|
value: alertEcsData.dll?.path ?? '',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
field: 'dll.code_signature.subject_name',
|
|
||||||
operator: 'included' as const,
|
|
||||||
type: 'match' as const,
|
|
||||||
value: alertEcsData.dll?.code_signature?.subject_name ?? '',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
field: 'dll.pe.original_file_name',
|
field: 'dll.pe.original_file_name',
|
||||||
operator: 'included' as const,
|
operator: 'included' as const,
|
||||||
|
@ -741,10 +779,28 @@ export const getPrepopulatedBehaviorException = ({
|
||||||
type: 'match' as const,
|
type: 'match' as const,
|
||||||
value: alertEcsData.user?.id ?? '',
|
value: alertEcsData.user?.id ?? '',
|
||||||
},
|
},
|
||||||
]);
|
];
|
||||||
|
|
||||||
|
const entriesToAdd = () => {
|
||||||
|
if (!isLinux) {
|
||||||
|
if (processCodeSignature !== undefined && dllCodeSignature !== undefined) {
|
||||||
|
return addIdToEntries(
|
||||||
|
filterEmptyExceptionEntries(commonFields.concat(processCodeSignature, dllCodeSignature))
|
||||||
|
);
|
||||||
|
} else if (processCodeSignature !== undefined) {
|
||||||
|
return addIdToEntries(
|
||||||
|
filterEmptyExceptionEntries(commonFields.concat(processCodeSignature))
|
||||||
|
);
|
||||||
|
} else if (dllCodeSignature !== undefined) {
|
||||||
|
return addIdToEntries(filterEmptyExceptionEntries(commonFields.concat(dllCodeSignature)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addIdToEntries(filterEmptyExceptionEntries(commonFields));
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...getNewExceptionItem({ listId, namespaceType: listNamespace, name }),
|
...getNewExceptionItem({ listId, namespaceType: listNamespace, name }),
|
||||||
entries: addIdToEntries(entries),
|
entries: entriesToAdd(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -757,7 +813,6 @@ export const defaultEndpointExceptionItems = (
|
||||||
alertEcsData: Flattened<Ecs> & { 'event.code'?: string }
|
alertEcsData: Flattened<Ecs> & { 'event.code'?: string }
|
||||||
): ExceptionsBuilderExceptionItem[] => {
|
): ExceptionsBuilderExceptionItem[] => {
|
||||||
const eventCode = alertEcsData['event.code'] ?? alertEcsData.event?.code;
|
const eventCode = alertEcsData['event.code'] ?? alertEcsData.event?.code;
|
||||||
|
|
||||||
switch (eventCode) {
|
switch (eventCode) {
|
||||||
case 'behavior':
|
case 'behavior':
|
||||||
return [
|
return [
|
||||||
|
@ -787,26 +842,24 @@ export const defaultEndpointExceptionItems = (
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
case 'ransomware':
|
case 'ransomware':
|
||||||
return getProcessCodeSignature(alertEcsData).map((codeSignature) =>
|
return [
|
||||||
getPrepopulatedRansomwareException({
|
getPrepopulatedRansomwareException({
|
||||||
listId,
|
listId,
|
||||||
name,
|
name,
|
||||||
eventCode,
|
eventCode,
|
||||||
codeSignature,
|
|
||||||
alertEcsData,
|
alertEcsData,
|
||||||
})
|
}),
|
||||||
);
|
];
|
||||||
default:
|
default:
|
||||||
// By default return the standard prepopulated Endpoint Exception fields
|
// By default return the standard prepopulated Endpoint Exception fields
|
||||||
return getFileCodeSignature(alertEcsData).map((codeSignature) =>
|
return [
|
||||||
getPrepopulatedEndpointException({
|
getPrepopulatedEndpointException({
|
||||||
listId,
|
listId,
|
||||||
name,
|
name,
|
||||||
eventCode: eventCode ?? '',
|
eventCode: eventCode ?? '',
|
||||||
codeSignature,
|
|
||||||
alertEcsData,
|
alertEcsData,
|
||||||
})
|
}),
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ export interface ExceptionsPagination {
|
||||||
|
|
||||||
export interface FlattenedCodeSignature {
|
export interface FlattenedCodeSignature {
|
||||||
subject_name: string;
|
subject_name: string;
|
||||||
trusted: string;
|
trusted: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Flattened<T> = {
|
export type Flattened<T> = {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue