Skip to content

Commit

Permalink
[backend] Filter observables creation with refs from indicators (#5293)
Browse files Browse the repository at this point in the history
  • Loading branch information
SouadHadjiat committed Apr 3, 2024
1 parent 47d1225 commit eb146f8
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
} from '../../schema/general';
import { elCount } from '../../database/engine';
import { isEmptyField, READ_INDEX_STIX_DOMAIN_OBJECTS } from '../../database/utils';
import { cleanupIndicatorPattern, extractObservablesFromIndicatorPattern } from '../../utils/syntax';
import { cleanupIndicatorPattern, extractValidObservablesFromIndicatorPattern } from '../../utils/syntax';
import { computeValidPeriod } from './indicator-utils';
import { addFilter } from '../../utils/filtering/filtering-utils';
import type { AuthContext, AuthUser } from '../../types/user';
Expand Down Expand Up @@ -159,7 +159,7 @@ export const createObservablesFromIndicator = async (
indicator: StoreEntityIndicator,
) => {
const { pattern } = indicator;
const observables = extractObservablesFromIndicatorPattern(pattern);
const observables = extractValidObservablesFromIndicatorPattern(pattern);
const observablesToLink = [];
for (let index = 0; index < observables.length; index += 1) {
const observable = observables[index];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ import { createStixPattern } from '../../python/pythonBridge';
import { generateKeyValueForIndicator } from '../../domain/stixCyberObservable';
import { RELATION_BASED_ON } from '../../schema/stixCoreRelationship';
import type { StixRelation } from '../../types/stix-sro';
import { extractObservablesFromIndicatorPattern, STIX_PATTERN_TYPE } from '../../utils/syntax';
import { extractValidObservablesFromIndicatorPattern, STIX_PATTERN_TYPE } from '../../utils/syntax';
import { ENTITY_TYPE_CONTAINER_CASE_INCIDENT, type StixCaseIncident } from '../case/case-incident/case-incident-types';
import { isStixMatchFilterGroup } from '../../utils/filtering/filtering-stix/stix-filtering';
import { ENTITY_TYPE_INDICATOR, type StixIndicator } from '../indicator/indicator-types';
Expand Down Expand Up @@ -962,7 +962,7 @@ const PLAYBOOK_CREATE_OBSERVABLE_COMPONENT: PlaybookComponent<CreateObservableCo
for (let indexIndicator = 0; indexIndicator < indicators.length; indexIndicator += 1) {
const indicator = indicators[indexIndicator] as StixIndicator;
if (indicator.type === 'indicator') {
const observables = extractObservablesFromIndicatorPattern(indicator.pattern);
const observables = extractValidObservablesFromIndicatorPattern(indicator.pattern);
for (let indexObservable = 0; indexObservable < observables.length; indexObservable += 1) {
const observable = observables[indexObservable];
const description = indicator.description ?? `Simple observable of indicator {${indicator.name || indicator.pattern}}`;
Expand Down
15 changes: 15 additions & 0 deletions opencti-platform/opencti-graphql/src/utils/syntax.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,21 @@ export const extractObservablesFromIndicatorPattern = (pattern) => {
return observables;
};

export const validateObservableGeneration = (observableType, indicatorPattern) => {
if (observableType === C.ENTITY_NETWORK_TRAFFIC && (indicatorPattern.includes('dst_ref') || indicatorPattern.includes('src_ref'))) {
return false; // we can't create this type of observables (issue #5293)
}
if (observableType === C.ENTITY_EMAIL_MESSAGE && (indicatorPattern.includes('from_ref') || indicatorPattern.includes('sender_ref'))) {
return false; // we can't create this type of observables (issue #5293)
}
return true;
};

export const extractValidObservablesFromIndicatorPattern = (pattern) => {
const observables = extractObservablesFromIndicatorPattern(pattern);
return observables.filter((obs) => validateObservableGeneration(obs.type, pattern));
};

export const cleanupIndicatorPattern = (patternType, pattern) => {
if (pattern && patternType.toLowerCase() === STIX_PATTERN_TYPE) {
const grabInterestingTokens = (ctx, parser, acc) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import { cleanupIndicatorPattern, extractObservablesFromIndicatorPattern, STIX_PATTERN_TYPE } from '../../../src/utils/syntax';
import { cleanupIndicatorPattern, extractObservablesFromIndicatorPattern, STIX_PATTERN_TYPE, validateObservableGeneration } from '../../../src/utils/syntax';
import * as C from '../../../src/schema/stixCyberObservable';
import { computeValidPeriod, computeValidTTL, DEFAULT_INDICATOR_TTL } from '../../../src/modules/indicator/indicator-utils';
import { ADMIN_USER, testContext } from '../../utils/testQuery';
Expand Down Expand Up @@ -40,19 +40,37 @@ describe('indicator utils', () => {
expect(domainAndHostname[1].type).toEqual(C.ENTITY_DOMAIN_NAME);
expect(domainAndHostname[1].value).toEqual('www.5z8.info');
// simpleEmailAddress
const simpleEmailAddress = extractObservablesFromIndicatorPattern('[email-message:sender_ref.value = \'jdoe@example.com\' AND email-message:subject = \'Conference Info\']');
expect(simpleEmailAddress.length).toEqual(1);
expect(simpleEmailAddress[0].type).toEqual(C.ENTITY_EMAIL_MESSAGE);
expect(simpleEmailAddress[0].subject).toEqual('Conference Info');
const simpleEmailMessage = extractObservablesFromIndicatorPattern('[email-message:sender_ref.value = \'jdoe@example.com\' AND email-message:subject = \'Conference Info\']');
expect(simpleEmailMessage.length).toEqual(1);
expect(simpleEmailMessage[0].type).toEqual(C.ENTITY_EMAIL_MESSAGE);
expect(simpleEmailMessage[0].subject).toEqual('Conference Info'); // we only extract the subject, without the sender_ref
// simpleUrl
const simpleUrl = extractObservablesFromIndicatorPattern('[url:value = \'http://localhost.com\']');
expect(simpleUrl.length).toEqual(1);
expect(simpleUrl[0].type).toEqual(C.ENTITY_URL);
expect(simpleUrl[0].value).toEqual('http://localhost.com');
// network traffic
const networkTrafficPort = extractObservablesFromIndicatorPattern('[network-traffic:dst_ref.value = \'127.0.0.1\' AND network-traffic:dst_port = 443]');
expect(networkTrafficPort.length).toEqual(1);
expect(networkTrafficPort[0].type).toEqual(C.ENTITY_NETWORK_TRAFFIC);
expect(networkTrafficPort[0].dst_port).toEqual('443'); // we only extract dst_port, not dst_ref

const networkTrafficIP = extractObservablesFromIndicatorPattern('[network-traffic:dst_ref.type = \'ipv4-addr\' AND network-traffic:dst_ref.value = \'203.0.113.33/32\']');
expect(networkTrafficIP.length).toEqual(0); // we don't know how to extract dst_ref for now
// Unknown type
const unknown = extractObservablesFromIndicatorPattern('[x-company-type:value = \'http://localhost.com\']');
expect(unknown.length).toEqual(0);
});
it('should validate observables extracted before creation', async () => {
const networkTrafficWithDstRef = validateObservableGeneration(C.ENTITY_NETWORK_TRAFFIC, "[network-traffic:dst_ref.type = 'ipv4-addr' AND network-traffic:dst_ref.value = '203.0.113.33/32']");
expect(networkTrafficWithDstRef).toBeFalsy();
const networkTrafficWithDstRefAndPort = validateObservableGeneration(C.ENTITY_NETWORK_TRAFFIC, "[network-traffic:dst_ref.value = '127.0.0.1' AND network-traffic:dst_port = 443]");
expect(networkTrafficWithDstRefAndPort).toBeFalsy();
const emailMessageWithFromRef = validateObservableGeneration(C.ENTITY_EMAIL_MESSAGE, "[email-message:sender_ref.value = 'jdoe@example.com' AND email-message:subject = 'Bad subject'");
expect(emailMessageWithFromRef).toBeFalsy();
const emailMessageSubject = validateObservableGeneration(C.ENTITY_EMAIL_MESSAGE, "[email-message:subject = 'Bad subject']");
expect(emailMessageSubject).toBeTruthy();
});
it('should indicator cleaned', async () => {
const testIndicatorPattern = (from: string, expectation: string) => {
const formattedPattern = cleanupIndicatorPattern(STIX_PATTERN_TYPE, from);
Expand Down

0 comments on commit eb146f8

Please sign in to comment.