Skip to content

Commit

Permalink
Load log type from log source if present (#894)
Browse files Browse the repository at this point in the history
* load log type from log source field of imported rule

Signed-off-by: Amardeepsingh Siglani <amardeep7194@gmail.com>

* improved logic to find log type

Signed-off-by: Amardeepsingh Siglani <amardeep7194@gmail.com>

* added cypress test; code simplified

Signed-off-by: Amardeepsingh Siglani <amardeep7194@gmail.com>

---------

Signed-off-by: Amardeepsingh Siglani <amardeep7194@gmail.com>
  • Loading branch information
amsiglan authored Mar 13, 2024
1 parent 3812afd commit 533cbcc
Show file tree
Hide file tree
Showing 13 changed files with 76 additions and 46 deletions.
26 changes: 26 additions & 0 deletions cypress/fixtures/sample_aws_s3_rule_to_import.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
title: Moriya Rootkit
id: 25b9c01c-350d-4b95-bed1-836d04a4f324
description: Detects the use of Moriya rootkit as described in the securelist Operation TunnelSnake report
status: experimental
author: Bhabesh Raj
date: 2021/05/06
modified: 2021/11/30
references:
- https://securelist.com/operation-tunnelsnake-and-moriya-rootkit/101831
tags:
- attack.persistence
- attack.privilege_escalation
- attack.t1543.003
logsource:
product: d3
category: s3
service: azure
detection:
selection:
Provider_Name: 'Service Control Manager'
EventID: 2100
ServiceName: ZzNetSvc
condition: selection
level: critical
falsepositives:
- Unknown
9 changes: 9 additions & 0 deletions cypress/integration/2_rules.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ const checkRulesFlyout = () => {
};

const getCreateButton = () => cy.get('[data-test-subj="create_rule_button"]');
const getImportButton = () => cy.get('[data-test-subj="import_rule_button"]');
const getImportRuleFilePicker = () => cy.get('[data-test-subj="import_rule_file_picker"]');
const getNameField = () => cy.getFieldByLabel('Rule name');
const getRuleStatusField = () => cy.getFieldByLabel('Rule Status');
const getDescriptionField = () => cy.getFieldByLabel('Description - optional');
Expand Down Expand Up @@ -570,6 +572,13 @@ describe('Rules', () => {
checkRulesFlyout();
});

it('...can be imported with log type', () => {
getImportButton().click({ force: true });
getImportRuleFilePicker().selectFile('./cypress/fixtures/sample_aws_s3_rule_to_import.yml');
// Check that AWS S3 log type is set.
cy.contains('AWS S3');
});

it('...can be deleted', () => {
setupIntercept(cy, `/rules/_search`, 'getRules');

Expand Down
6 changes: 5 additions & 1 deletion models/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
export interface Rule {
id: string;
category: string;
log_source: string;
log_source: {
product?: string;
category?: string;
service?: string;
};
title: string;
description: string;
tags: Array<{ value: string }>;
Expand Down
10 changes: 3 additions & 7 deletions opensearch_dashboards.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@
"id": "securityAnalyticsDashboards",
"version": "3.0.0.0",
"opensearchDashboardsVersion": "3.0.0",
"configPath": [
"opensearch_security_analytics"
],
"requiredPlugins": [
"data"
],
"configPath": ["opensearch_security_analytics"],
"requiredPlugins": ["data"],
"server": true,
"ui": true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('<RuleContentYamlViewer /> spec', () => {
value: 'attack.t1543.003',
},
],
log_source: '',
log_source: {},
detection:
'selection:\n Provider_Name: Service Control Manager\n EventID: 7045\n ServiceName: ZzNetSvc\ncondition: selection\n',
level: 'high',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ruleStatus } from '../../utils/constants';

export interface RuleEditorFormModel {
id: string;
log_source: string;
log_source: { product?: string; category?: string; service?: string };
logType: string;
name: string;
description: string;
Expand All @@ -22,7 +22,7 @@ export interface RuleEditorFormModel {

export const ruleEditorStateDefaultValue: RuleEditorFormModel = {
id: '25b9c01c-350d-4b95-bed1-836d04a4f324',
log_source: '',
log_source: {},
logType: '',
name: '',
description: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('<YamlRuleEditorComponent /> spec', () => {
value: 'attack.t1543.003',
},
],
log_source: '',
log_source: {},
detection:
'selection:\n Provider_Name: Service Control Manager\n EventID: 7045\n ServiceName: ZzNetSvc\ncondition: selection\n',
level: 'high',
Expand Down Expand Up @@ -80,7 +80,7 @@ describe('<YamlRuleEditorComponent /> spec', () => {
value: 'attack.t1543.003',
},
],
log_source: '',
log_source: {},
detection:
'selection:\n Provider_Name: Service Control Manager\n EventID: 7045\n ServiceName: ZzNetSvc\ncondition: selection\n',
level: 'high',
Expand Down
6 changes: 5 additions & 1 deletion public/pages/Rules/components/RuleEditor/mappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { Rule } from '../../../../../models/interfaces';
import { getLogTypeFromLogSource } from '../../utils/helpers';
import { RuleEditorFormModel, ruleEditorStateDefaultValue } from './RuleEditorFormModel';

export const mapFormToRule = (formState: RuleEditorFormModel): Rule => {
Expand All @@ -25,10 +26,13 @@ export const mapFormToRule = (formState: RuleEditorFormModel): Rule => {
};

export const mapRuleToForm = (rule: Rule): RuleEditorFormModel => {
// get category from log_source
const logType = rule.category || getLogTypeFromLogSource(rule.log_source);

return {
id: rule.id,
log_source: rule.log_source,
logType: rule.category,
logType: logType || '',
name: rule.title,
description: rule.description,
status: rule.status,
Expand Down
32 changes: 3 additions & 29 deletions public/pages/Rules/containers/ImportRule/ImportRule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import { dump, load } from 'js-yaml';
import { ContentPanel } from '../../../../components/ContentPanel';
import { NotificationsStart } from 'opensearch-dashboards/public';
import { CoreServicesContext } from '../../../../components/core_services';
import { setBreadCrumb, validateRule } from '../../utils/helpers';
import { DataStore } from '../../../../store/DataStore';
import { setBreadCrumb } from '../../utils/helpers';
import { yamlMediaTypes } from '../../utils/constants';

export interface ImportRuleProps {
Expand Down Expand Up @@ -64,7 +63,7 @@ export const ImportRule: React.FC<ImportRuleProps> = ({ history, services, notif
references:
jsonContent.references?.map((reference: string) => ({ value: reference })) || [],
tags: jsonContent.tags?.map((tag: string) => ({ value: tag })) || [],
log_source: jsonContent.logsource || '',
log_source: jsonContent.logsource || {},
detection: detectionYaml,
level: jsonContent.level || '',
false_positives:
Expand Down Expand Up @@ -105,6 +104,7 @@ export const ImportRule: React.FC<ImportRuleProps> = ({ history, services, notif
multiple={false}
aria-label="file picker"
isInvalid={!!fileError}
data-test-subj="import_rule_file_picker"
/>
{fileError && <div style={{ color: 'red', margin: '0 auto' }}>Error: {fileError}</div>}
</ContentPanel>
Expand All @@ -119,31 +119,5 @@ export const ImportRule: React.FC<ImportRuleProps> = ({ history, services, notif
setBreadCrumb(BREADCRUMBS.RULES_IMPORT, context?.chrome.setBreadcrumbs);
}, [fileError, onChange]);

const footerActions: React.FC<{ rule: Rule }> = ({ rule }) => {
const onCreate = async () => {
if (!validateRule(rule, notifications!, 'create')) {
return;
}
const response = await DataStore.rules.createRule(rule);

if (response) {
history.replace(ROUTES.RULES);
}
};

return (
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButton onClick={() => history.replace(ROUTES.RULES)}>Cancel</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton fill onClick={onCreate}>
Create
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
);
};

return content;
};
2 changes: 2 additions & 0 deletions public/pages/Rules/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,6 @@ export const ruleSource: string[] = ['Standard', 'Custom'];

export const ruleStatus: string[] = ['experimental', 'test', 'stable'];

export const sigmaRuleLogSourceFields = ['product', 'category', 'service'];

export const yamlMediaTypes = new Set(['application/x-yaml', 'text/yaml', 'text/x-yaml']);
17 changes: 16 additions & 1 deletion public/pages/Rules/utils/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
formatRuleType,
getLogTypeFilterOptions,
} from '../../../utils/helpers';
import { ruleSeverity, ruleSource } from './constants';
import { ruleSeverity, ruleSource, ruleTypes, sigmaRuleLogSourceFields } from './constants';
import { Search } from '@opensearch-project/oui/src/eui_components/basic_table';
import { Rule } from '../../../../models/interfaces';
import { NotificationsStart } from 'opensearch-dashboards/public';
Expand Down Expand Up @@ -177,3 +177,18 @@ export function setBreadCrumb(
) {
breadCrumbSetter?.([BREADCRUMBS.SECURITY_ANALYTICS, BREADCRUMBS.RULES, breadCrumb]);
}

export function getLogTypeFromLogSource(logSource: { [k: string]: string }) {
const logTypes = new Set(ruleTypes.map(({ value }) => value));
let logType;

for (let field of sigmaRuleLogSourceFields) {
logType = logSource[field];

if (logType && logTypes.has(logType)) {
break;
}
}

return logType;
}
2 changes: 1 addition & 1 deletion public/pages/Rules/utils/mappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const mapYamlObjectToRule = (obj: any): Rule => {
const rule: Rule = {
id: obj.id,
category: obj.logsource ? obj.logsource.product : undefined,
log_source: '',
log_source: {},
title: obj.title,
description: obj.description,
tags: obj.tags ? obj.tags.map((tag: string) => ({ value: tag })) : undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ruleStatus } from '../../../../../public/pages/Rules/utils/constants';
export default {
initialValue: {
id: '25b9c01c-350d-4b95-bed1-836d04a4f324',
log_source: '',
log_source: {},
logType: '',
name: '',
description: '',
Expand Down

0 comments on commit 533cbcc

Please sign in to comment.