mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Security Solution] File paths for Blocklist Windows and Mac should be case insensitive (#164200)
## Summary
This fixes a bug where Windows and Mac Blocklist file path entries
should be passed as case insensitive. This is because Mac and Windows
are caseless for most use cases.
Bug ticket: https://github.com/elastic/kibana/issues/158581
Here is how it will be displayed in the UI:
<img width="1728" alt="image"
src="a3006397
-f49e-4de0-818d-94e2de20dba3">
Here are the breakdown of the artifacts after the fix:
Linux:
```
-------------------------------------------------------------------
Policy: Protect
Manifest: 1.0.6 | v1
Artifact: endpoint-blocklist-linux-v1
Relative URL: /api/fleet/artifacts/endpoint-blocklist-linux-v1/f33e6890aeced00861c26a08121dd42d2d29ba08abfeb3c065d0447e32e18640
Encoded SHA256: a907835be40af89b8b7aa23a6efc66c01ceaa5a19622edd378139319f3ca5fa0
Decoded SHA256: f33e6890aeced00861c26a08121dd42d2d29ba08abfeb3c065d0447e32e18640
-------------------------------------------------------------------
{
"entries": [
{
"type": "simple",
"entries": [
{
"field": "file.path",
"operator": "included",
"type": "exact_cased_any",
"value": [
"/opt/bin/bin.exe"
]
}
]
}
]
}
```
Mac:
```
-------------------------------------------------------------------
Policy: Protect
Manifest: 1.0.6 | v1
Artifact: endpoint-blocklist-macos-v1
Relative URL: /api/fleet/artifacts/endpoint-blocklist-macos-v1/b28e7978da4314ebc2c94770e0638fc4b2270f9dc17a11d6d32b8634b1fbec0f
Encoded SHA256: 4f3e80d688f5cae4bf6a88b0704e37909f9fa4f47fe8325b7b154cddd46a2db9
Decoded SHA256: b28e7978da4314ebc2c94770e0638fc4b2270f9dc17a11d6d32b8634b1fbec0f
-------------------------------------------------------------------
{
"entries": [
{
"type": "simple",
"entries": [
{
"field": "file.path",
"operator": "included",
"type": "exact_caseless_any",
"value": [
"/opt/exe.exe"
]
}
]
}
```
Windows:
```
-------------------------------------------------------------------
Policy: Protect
Manifest: 1.0.6 | v1
Artifact: endpoint-blocklist-windows-v1
Relative URL: /api/fleet/artifacts/endpoint-blocklist-windows-v1/2a6fcc67c696ad4e29d91f8b685bff46977198cd34b9a61e8003d55b78dff6ac
Encoded SHA256: c6e045fce97651336eeb400f0123541475b940e3aa38ce721f299585683da288
Decoded SHA256: 2a6fcc67c696ad4e29d91f8b685bff46977198cd34b9a61e8003d55b78dff6ac
-------------------------------------------------------------------
{
"entries": [
{
"type": "simple",
"entries": [
{
"field": "file.path",
"operator": "included",
"type": "exact_caseless_any",
"value": [
"C:\\path\\path.exe"
]
}
]
}
]
}
```
### Checklist
Delete any items that are not applicable to this PR.
- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
---------
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
011ae97061
commit
88bd71c077
7 changed files with 83 additions and 14 deletions
|
@ -33,7 +33,11 @@ export type TrustedAppConditionEntryField =
|
|||
| 'process.hash.*'
|
||||
| 'process.executable.caseless'
|
||||
| 'process.Ext.code_signature';
|
||||
export type BlocklistConditionEntryField = 'file.hash.*' | 'file.path' | 'file.Ext.code_signature';
|
||||
export type BlocklistConditionEntryField =
|
||||
| 'file.hash.*'
|
||||
| 'file.path'
|
||||
| 'file.Ext.code_signature'
|
||||
| 'file.path.caseless';
|
||||
export type AllConditionEntryFields =
|
||||
| TrustedAppConditionEntryField
|
||||
| BlocklistConditionEntryField
|
||||
|
|
|
@ -358,7 +358,7 @@ export const getArtifactsListTestsData = (): ArtifactsFixtureType[] => [
|
|||
},
|
||||
{
|
||||
type: 'click',
|
||||
selector: 'blocklist-form-file.path',
|
||||
selector: 'blocklist-form-file.path.caseless',
|
||||
},
|
||||
{
|
||||
type: 'click',
|
||||
|
@ -379,7 +379,7 @@ export const getArtifactsListTestsData = (): ArtifactsFixtureType[] => [
|
|||
{
|
||||
selector: 'blocklistPage-card-criteriaConditions',
|
||||
value:
|
||||
'OSIS WindowsAND file.pathis one of\nc:\\randomFolder\\randomFile.exe\nc:\\randomFolder\\randomFile2.exe',
|
||||
'OSIS WindowsAND file.path.caselessis one of\nc:\\randomFolder\\randomFile.exe\nc:\\randomFolder\\randomFile2.exe',
|
||||
},
|
||||
{
|
||||
selector: 'blocklistPage-card-header-title',
|
||||
|
|
|
@ -76,6 +76,12 @@ export const CONDITION_FIELD_TITLE: { [K in BlocklistConditionEntryField]: strin
|
|||
'file.path': i18n.translate('xpack.securitySolution.blocklist.entry.field.path', {
|
||||
defaultMessage: 'Path',
|
||||
}),
|
||||
'file.path.caseless': i18n.translate(
|
||||
'xpack.securitySolution.blocklist.entry.field.path.caseless',
|
||||
{
|
||||
defaultMessage: 'Path',
|
||||
}
|
||||
),
|
||||
'file.Ext.code_signature': i18n.translate(
|
||||
'xpack.securitySolution.blocklist.entry.field.signature',
|
||||
{ defaultMessage: 'Signature' }
|
||||
|
@ -89,6 +95,12 @@ export const CONDITION_FIELD_DESCRIPTION: { [K in BlocklistConditionEntryField]:
|
|||
'file.path': i18n.translate('xpack.securitySolution.blocklist.entry.field.description.path', {
|
||||
defaultMessage: 'The full path of the application',
|
||||
}),
|
||||
'file.path.caseless': i18n.translate(
|
||||
'xpack.securitySolution.blocklist.entry.field.description.path.caseless',
|
||||
{
|
||||
defaultMessage: 'The full path of the application (case insenstive)',
|
||||
}
|
||||
),
|
||||
'file.Ext.code_signature': i18n.translate(
|
||||
'xpack.securitySolution.blocklist.entry.field.description.signature',
|
||||
{ defaultMessage: 'The signer of the application' }
|
||||
|
|
|
@ -225,6 +225,38 @@ describe('blocklist form', () => {
|
|||
userEvent.click(screen.getByRole('option', { name: /path/i }));
|
||||
const expected = createOnChangeArgs({
|
||||
item: createItem({
|
||||
entries: [createEntry('file.path.caseless', [])],
|
||||
}),
|
||||
});
|
||||
expect(onChangeSpy).toHaveBeenCalledWith(expected);
|
||||
});
|
||||
|
||||
it('should correctly create `file.path.caseless` when Mac OS is selected', async () => {
|
||||
render(createProps({ item: createItem({ os_types: [OperatingSystem.MAC] }) }));
|
||||
expect(screen.getByTestId('blocklist-form-os-select').textContent).toEqual('Mac');
|
||||
|
||||
userEvent.click(screen.getByTestId('blocklist-form-field-select'));
|
||||
await waitForEuiPopoverOpen();
|
||||
userEvent.click(screen.getByRole('option', { name: /path/i }));
|
||||
const expected = createOnChangeArgs({
|
||||
item: createItem({
|
||||
os_types: [OperatingSystem.MAC],
|
||||
entries: [createEntry('file.path.caseless', [])],
|
||||
}),
|
||||
});
|
||||
expect(onChangeSpy).toHaveBeenCalledWith(expected);
|
||||
});
|
||||
|
||||
it('should correctly create `file.path` when Linux is selected', async () => {
|
||||
render(createProps({ item: createItem({ os_types: [OperatingSystem.LINUX] }) }));
|
||||
expect(screen.getByTestId('blocklist-form-os-select').textContent).toEqual('Linux');
|
||||
|
||||
userEvent.click(screen.getByTestId('blocklist-form-field-select'));
|
||||
await waitForEuiPopoverOpen();
|
||||
userEvent.click(screen.getByRole('option', { name: /path/i }));
|
||||
const expected = createOnChangeArgs({
|
||||
item: createItem({
|
||||
os_types: [OperatingSystem.LINUX],
|
||||
entries: [createEntry('file.path', [])],
|
||||
}),
|
||||
});
|
||||
|
|
|
@ -178,14 +178,31 @@ export const BlockListForm = memo<ArtifactFormComponentProps>(
|
|||
);
|
||||
|
||||
const fieldOptions: Array<EuiSuperSelectOption<BlocklistConditionEntryField>> = useMemo(() => {
|
||||
const selectableFields: Array<EuiSuperSelectOption<BlocklistConditionEntryField>> = (
|
||||
['file.hash.*', 'file.path'] as BlocklistConditionEntryField[]
|
||||
).map((field) => ({
|
||||
value: field,
|
||||
inputDisplay: CONDITION_FIELD_TITLE[field],
|
||||
dropdownDisplay: getDropdownDisplay(field),
|
||||
'data-test-subj': getTestId(field),
|
||||
}));
|
||||
const selectableFields: Array<EuiSuperSelectOption<BlocklistConditionEntryField>> = [];
|
||||
|
||||
selectableFields.push({
|
||||
value: 'file.hash.*',
|
||||
inputDisplay: CONDITION_FIELD_TITLE['file.hash.*'],
|
||||
dropdownDisplay: getDropdownDisplay('file.hash.*'),
|
||||
'data-test-subj': getTestId('file.hash.*'),
|
||||
});
|
||||
|
||||
if (selectedOs === OperatingSystem.LINUX) {
|
||||
selectableFields.push({
|
||||
value: 'file.path',
|
||||
inputDisplay: CONDITION_FIELD_TITLE['file.path'],
|
||||
dropdownDisplay: getDropdownDisplay('file.path'),
|
||||
'data-test-subj': getTestId('file.path'),
|
||||
});
|
||||
} else {
|
||||
selectableFields.push({
|
||||
value: 'file.path.caseless',
|
||||
inputDisplay: CONDITION_FIELD_TITLE['file.path.caseless'],
|
||||
dropdownDisplay: getDropdownDisplay('file.path.caseless'),
|
||||
'data-test-subj': getTestId('file.path.caseless'),
|
||||
});
|
||||
}
|
||||
|
||||
if (selectedOs === OperatingSystem.WINDOWS) {
|
||||
selectableFields.push({
|
||||
value: 'file.Ext.code_signature',
|
||||
|
|
|
@ -21,12 +21,16 @@ import { isValidHash } from '../../../../common/endpoint/service/artifacts/valid
|
|||
import { EndpointArtifactExceptionValidationError } from './errors';
|
||||
|
||||
const allowedHashes: Readonly<string[]> = ['file.hash.md5', 'file.hash.sha1', 'file.hash.sha256'];
|
||||
const allowedFilePaths: Readonly<string[]> = ['file.path', 'file.path.caseless'];
|
||||
|
||||
const FileHashField = schema.oneOf(
|
||||
allowedHashes.map((hash) => schema.literal(hash)) as [Type<string>]
|
||||
);
|
||||
|
||||
const FilePath = schema.literal('file.path');
|
||||
const FilePath = schema.oneOf(
|
||||
allowedFilePaths.map((path) => schema.literal(path)) as [Type<string>]
|
||||
);
|
||||
|
||||
const FileCodeSigner = schema.literal('file.Ext.code_signature');
|
||||
|
||||
const ConditionEntryTypeSchema = schema.literal('match_any');
|
||||
|
|
|
@ -423,7 +423,7 @@ export const getArtifactsListTestsData = () => [
|
|||
{
|
||||
selector: 'blocklistPage-card-criteriaConditions',
|
||||
value:
|
||||
'OSIS Windows\nAND file.pathIS ONE OF\nc:\\randomFolder\\randomFile.exe\nc:\\randomFolder\\randomFile2.exe',
|
||||
'OSIS Windows\nAND file.path.caselessIS ONE OF\nc:\\randomFolder\\randomFile.exe\nc:\\randomFolder\\randomFile2.exe',
|
||||
},
|
||||
{
|
||||
selector: 'blocklistPage-card-header-title',
|
||||
|
@ -499,7 +499,7 @@ export const getArtifactsListTestsData = () => [
|
|||
{
|
||||
field: 'file.path',
|
||||
operator: 'included',
|
||||
type: 'exact_cased_any',
|
||||
type: 'exact_caseless_any',
|
||||
value: ['c:\\randomFolder\\randomFile.exe', ' c:\\randomFolder\\randomFile2.exe'],
|
||||
},
|
||||
],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue