Skip to content

Commit

Permalink
[Security Solution][Event Filters] Warning callout for incomplete cod…
Browse files Browse the repository at this point in the history
…e signature entries (elastic#193749)

## Summary
Navigate to Security Solution > Manage > Event Filters > Add Event
Filter

- [x] Warning callout shown when code signature field is incomplete
(i.e. `process.code_signature.subject_name` w/o
`process.code_signature.trusted` or vice versa)
- [x] For mac operating systems, `process.code_signature.team_id` is
also accepted as an equivalent to `subject_name`
- [x] Warning callout is also shown for nested entries for this code
signature field: `process.Ext.code_signature`
- [x] Unit Tests

# Screenshots

![image](https://github.com/user-attachments/assets/e77cffa7-8b60-4441-9319-aa9964224bb9)

![image](https://github.com/user-attachments/assets/6ec7c6a1-28e8-4f8e-a6aa-3e65b1e0ba1b)

MAC

![image](https://github.com/user-attachments/assets/86354b92-d7e3-44f1-8719-d9791dcaf9cd)

NESTED

![image](https://github.com/user-attachments/assets/1392d7b2-0b63-40b8-95be-8a5bfa2e0af1)

Followup prs: need to address user being allowed to choose the nested
field: `process.Ext.code_signature` for a non-nested entry, need to
address what happens when a user chooses `false` instead of true for the
`trusted` field option

---------

Co-authored-by: kibanamachine <[email protected]>
(cherry picked from commit 61c9137)
  • Loading branch information
parkiino committed Oct 7, 2024
1 parent a89a538 commit 0814856
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ export * from './src/list_header';
export * from './src/header_menu';
export * from './src/generate_linked_rules_menu_item';
export * from './src/wildcard_with_wrong_operator_callout';
export * from './src/partial_code_signature_callout';
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import React from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';

import { EuiCallOut } from '@elastic/eui';

export const PartialCodeSignatureCallout = () => {
return (
<EuiCallOut
title={i18n.translate('exceptionList-components.partialCodeSignatureCallout.title', {
defaultMessage: 'Please review your entries',
})}
iconType="warning"
color="warning"
size="s"
data-test-subj="partialCodeSignatureCallout"
>
<FormattedMessage
id="exceptionList-components.partialCodeSignatureCallout.body"
defaultMessage='Please review field values, as your filter criteria may be incomplete. We recommend both the signer name and trust status be included (using the "AND" operator) to avoid potential security gaps.'
tagName="p"
/>
</EuiCallOut>
);
};
115 changes: 114 additions & 1 deletion packages/kbn-securitysolution-list-utils/src/helpers/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { getMappingConflictsInfo, fieldSupportsMatches, hasWrongOperatorWithWildcard } from '.';
import {
getMappingConflictsInfo,
fieldSupportsMatches,
hasWrongOperatorWithWildcard,
hasPartialCodeSignatureEntry,
} from '.';

describe('Helpers', () => {
describe('getMappingConflictsInfo', () => {
Expand Down Expand Up @@ -261,4 +266,112 @@ describe('Helpers', () => {
).toBeTruthy();
});
});

describe('hasPartialCodeSignatureEntry', () => {
it('returns false if the entry has neither code signature subject name nor trusted field', () => {
expect(
hasPartialCodeSignatureEntry([
{
description: '',
name: '',
type: 'simple',
os_types: ['windows'],
entries: [{ type: 'match', value: 'asdf', field: 'someField', operator: 'excluded' }],
},
])
).toBeFalsy();
});
it('returns true if the entry has code signature subject name but not trusted field', () => {
expect(
hasPartialCodeSignatureEntry([
{
description: '',
name: '',
type: 'simple',
os_types: ['windows'],
entries: [
{
type: 'match',
value: 'asdf',
field: 'process.code_signature.subject_name',
operator: 'excluded',
},
],
},
])
).toBeTruthy();
});
it('returns true if the entry has code signature trusted but not the subject name field', () => {
expect(
hasPartialCodeSignatureEntry([
{
description: '',
name: '',
type: 'simple',
os_types: ['windows'],
entries: [
{
type: 'match',
value: 'asdf',
field: 'process.code_signature.trusted',
operator: 'excluded',
},
],
},
])
).toBeTruthy();
});
it('returns false if the entry has both code signature subject name and trusted field', () => {
expect(
hasPartialCodeSignatureEntry([
{
description: '',
name: '',
type: 'simple',
os_types: ['windows'],
entries: [
{
type: 'match',
value: 'asdf',
field: 'process.code_signature.subject_name',
operator: 'excluded',
},
{
type: 'match',
value: 'true',
field: 'process.code_signature.trusted',
operator: 'excluded',
},
],
},
])
).toBeFalsy();
});
it('returns false if the entry has both code signature team_id and trusted fields for mac os', () => {
expect(
hasPartialCodeSignatureEntry([
{
description: '',
name: '',
type: 'simple',
os_types: ['macos'],
entries: [
{
type: 'match',
value: 'asdf',
field: 'process.code_signature.team_id',
operator: 'excluded',
},
{
type: 'match',
value: 'true',
field: 'process.code_signature.trusted',
operator: 'excluded',
},
],
},
])
).toBeFalsy();
});
});
});
35 changes: 35 additions & 0 deletions packages/kbn-securitysolution-list-utils/src/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1052,3 +1052,38 @@ export const hasWrongOperatorWithWildcard = (
}
});
};

/**
* Event filters helper where given an exceptions list,
* determine if both 'subject_name' and 'trusted' are
* included in an entry with 'code_signature'
*/
export const hasPartialCodeSignatureEntry = (
items: ExceptionsBuilderReturnExceptionItem[]
): boolean => {
const { os_types: os = ['windows'], entries = [] } = items[0] || {};
let name = false;
let trusted = false;

for (const e of entries) {
if (e.type === 'nested' && e.field === 'process.Ext.code_signature') {
const includesNestedName = e.entries.some(
(nestedEntry) => nestedEntry.field === 'subject_name'
);
const includesNestedTrusted = e.entries.some(
(nestedEntry) => nestedEntry.field === 'trusted'
);
if (includesNestedName !== includesNestedTrusted) {
return true;
}
} else if (
e.field === 'process.code_signature.subject_name' ||
(os.includes('macos') && e.field === 'process.code_signature.team_id')
) {
name = true;
} else if (e.field === 'process.code_signature.trusted') {
trusted = true;
}
}
return name !== trusted;
};
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-t
import {
EVENT_FILTERS_OPERATORS,
hasWrongOperatorWithWildcard,
hasPartialCodeSignatureEntry,
} from '@kbn/securitysolution-list-utils';
import { WildCardWithWrongOperatorCallout } from '@kbn/securitysolution-exception-list-components';
import {
WildCardWithWrongOperatorCallout,
PartialCodeSignatureCallout,
} from '@kbn/securitysolution-exception-list-components';
import { OperatingSystem } from '@kbn/securitysolution-utils';

import { getExceptionBuilderComponentLazy } from '@kbn/lists-plugin/public';
Expand Down Expand Up @@ -171,6 +175,9 @@ export const EventFiltersForm: React.FC<ArtifactFormComponentProps & { allowSele
hasWrongOperatorWithWildcard([exception])
);

const [hasPartialCodeSignatureWarning, setHasPartialCodeSignatureWarning] =
useState<boolean>(false);

// This value has to be memoized to avoid infinite useEffect loop on useFetchIndex
const indexNames = useMemo(() => [eventsIndexPattern], []);
const [isIndexPatternLoading, { indexPatterns }] = useFetchIndex(
Expand Down Expand Up @@ -563,6 +570,7 @@ export const EventFiltersForm: React.FC<ArtifactFormComponentProps & { allowSele

// handle wildcard with wrong operator case
setHasWildcardWithWrongOperator(hasWrongOperatorWithWildcard(arg.exceptionItems));
setHasPartialCodeSignatureWarning(hasPartialCodeSignatureEntry(arg.exceptionItems));

const updatedItem: Partial<ArtifactFormComponentProps['item']> =
arg.exceptionItems[0] !== undefined
Expand Down Expand Up @@ -725,6 +733,7 @@ export const EventFiltersForm: React.FC<ArtifactFormComponentProps & { allowSele
<EuiHorizontalRule />
{criteriaSection}
{hasWildcardWithWrongOperator && <WildCardWithWrongOperatorCallout />}
{hasPartialCodeSignatureWarning && <PartialCodeSignatureCallout />}
{hasDuplicateFields && (
<>
<EuiSpacer size="xs" />
Expand Down

0 comments on commit 0814856

Please sign in to comment.