-
Notifications
You must be signed in to change notification settings - Fork 8.6k
[Security Solution] Populates threat.indicator.event with _source.event (#951) #95697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ | |
|
|
||
| import signalsMapping from './signals_mapping.json'; | ||
| import ecsMapping from './ecs_mapping.json'; | ||
| import indicatorMapping from './indicator_mapping.json'; | ||
|
|
||
| /** | ||
| @constant | ||
|
|
@@ -21,7 +22,7 @@ import ecsMapping from './ecs_mapping.json'; | |
| incremented by 10 in order to add "room" for the aforementioned patch | ||
| release | ||
| */ | ||
| export const SIGNALS_TEMPLATE_VERSION = 25; | ||
| export const SIGNALS_TEMPLATE_VERSION = 26; | ||
| export const MIN_EQL_RULE_INDEX_VERSION = 2; | ||
|
|
||
| export const getSignalsTemplate = (index: string) => { | ||
|
|
@@ -45,6 +46,13 @@ export const getSignalsTemplate = (index: string) => { | |
| properties: { | ||
| ...ecsMapping.mappings.properties, | ||
| signal: signalsMapping.mappings.properties.signal, | ||
| threat: { | ||
| ...ecsMapping.mappings.properties.threat, | ||
| properties: { | ||
| ...ecsMapping.mappings.properties.threat.properties, | ||
| ...indicatorMapping, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this is correct; we want these to be part of the nested
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hey thanks for the catch |
||
| }, | ||
| }, | ||
| }, | ||
| _meta: { | ||
| version: SIGNALS_TEMPLATE_VERSION, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| { | ||
| "event": { | ||
| "properties": { | ||
| "action": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| }, | ||
| "category": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| }, | ||
| "code": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| }, | ||
| "created": { | ||
| "type": "date" | ||
| }, | ||
| "dataset": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| }, | ||
| "duration": { | ||
| "type": "long" | ||
| }, | ||
| "end": { | ||
| "type": "date" | ||
| }, | ||
| "hash": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| }, | ||
| "id": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| }, | ||
| "ingested": { | ||
| "type": "date" | ||
| }, | ||
| "kind": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| }, | ||
| "module": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| }, | ||
| "original": { | ||
| "doc_values": false, | ||
| "ignore_above": 1024, | ||
| "index": false, | ||
| "type": "keyword" | ||
| }, | ||
| "outcome": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| }, | ||
| "provider": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| }, | ||
| "reference": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| }, | ||
| "risk_score": { | ||
| "type": "float" | ||
| }, | ||
| "risk_score_norm": { | ||
| "type": "float" | ||
| }, | ||
| "sequence": { | ||
| "type": "long" | ||
| }, | ||
| "severity": { | ||
| "type": "long" | ||
| }, | ||
| "start": { | ||
| "type": "date" | ||
| }, | ||
| "timezone": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| }, | ||
| "type": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| }, | ||
| "url": { | ||
| "ignore_above": 1024, | ||
| "type": "keyword" | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -83,6 +83,7 @@ describe('buildMatchedIndicator', () => { | |
| getThreatListItemMock({ | ||
| _id: '123', | ||
| _source: { | ||
| event: { dataset: 'abuse.ch', reference: 'https://test.com' }, | ||
| threat: { indicator: { domain: 'domain_1', other: 'other_1', type: 'type_1' } }, | ||
| }, | ||
| }), | ||
|
|
@@ -117,6 +118,16 @@ describe('buildMatchedIndicator', () => { | |
| expect(get(indicator, 'matched.atomic')).toEqual('domain_1'); | ||
| }); | ||
|
|
||
| it('returns event values as a part of threat', () => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
| const [indicator] = buildMatchedIndicator({ | ||
| queries, | ||
| threats, | ||
| indicatorPath, | ||
| }); | ||
| const expectedEvent = threats[0]._source!.event; | ||
| expect(get(indicator, 'event')).toEqual(expectedEvent); | ||
| }); | ||
|
|
||
| it('returns the _id of the matched indicator as matched.id', () => { | ||
| const [indicator] = buildMatchedIndicator({ | ||
| queries, | ||
|
|
@@ -162,12 +173,16 @@ describe('buildMatchedIndicator', () => { | |
| getThreatListItemMock({ | ||
| _id: '123', | ||
| _source: { | ||
| threat: { indicator: { domain: 'domain_1', other: 'other_1', type: 'type_1' } }, | ||
| event: { reference: 'https://test.com' }, | ||
| threat: { | ||
| indicator: { domain: 'domain_1', other: 'other_1', type: 'type_1' }, | ||
| }, | ||
| }, | ||
| }), | ||
| getThreatListItemMock({ | ||
| _id: '456', | ||
| _source: { | ||
| event: { reference: 'https://test2.com' }, | ||
| threat: { indicator: { domain: 'domain_1', other: 'other_1', type: 'type_1' } }, | ||
| }, | ||
| }), | ||
|
|
@@ -205,6 +220,10 @@ describe('buildMatchedIndicator', () => { | |
| }, | ||
| other: 'other_1', | ||
| type: 'type_1', | ||
| event: { | ||
| reference: 'https://test.com', | ||
| dataset: 'abuse.ch', | ||
| }, | ||
| }, | ||
| ]); | ||
| }); | ||
|
|
@@ -214,6 +233,9 @@ describe('buildMatchedIndicator', () => { | |
| getThreatListItemMock({ | ||
| _id: '123', | ||
| _source: { | ||
| event: { | ||
| reference: 'https://test3.com', | ||
| }, | ||
| 'threat.indicator.domain': 'domain_1', | ||
| custom: { | ||
| indicator: { | ||
|
|
@@ -244,6 +266,9 @@ describe('buildMatchedIndicator', () => { | |
| type: 'indicator_type', | ||
| }, | ||
| type: 'indicator_type', | ||
| event: { | ||
| reference: 'https://test3.com', | ||
| }, | ||
| }, | ||
| ]); | ||
| }); | ||
|
|
@@ -307,6 +332,9 @@ describe('buildMatchedIndicator', () => { | |
| getThreatListItemMock({ | ||
| _id: '123', | ||
| _source: { | ||
| event: { | ||
| reference: 'https://test4.com', | ||
| }, | ||
| threat: { | ||
| indicator: [ | ||
| { domain: 'foo', type: 'first' }, | ||
|
|
@@ -334,6 +362,9 @@ describe('buildMatchedIndicator', () => { | |
| type: 'first', | ||
| }, | ||
| type: 'first', | ||
| event: { | ||
| reference: 'https://test4.com', | ||
| }, | ||
| }, | ||
| ]); | ||
| }); | ||
|
|
@@ -392,6 +423,9 @@ describe('enrichSignalThreatMatches', () => { | |
| getThreatListItemMock({ | ||
| _id: '123', | ||
| _source: { | ||
| event: { | ||
| category: 'malware', | ||
| }, | ||
| threat: { indicator: { domain: 'domain_1', other: 'other_1', type: 'type_1' } }, | ||
| }, | ||
| }), | ||
|
|
@@ -419,7 +453,11 @@ describe('enrichSignalThreatMatches', () => { | |
|
|
||
| it('preserves existing threat.indicator objects on signals', async () => { | ||
| const signalHit = getSignalHitMock({ | ||
| _source: { '@timestamp': 'mocked', threat: { indicator: [{ existing: 'indicator' }] } }, | ||
| _source: { | ||
| '@timestamp': 'mocked', | ||
| event: { category: 'malware' }, | ||
| threat: { indicator: [{ existing: 'indicator' }] }, | ||
| }, | ||
| matched_queries: [matchedQuery], | ||
| }); | ||
| const signals = getSignalsResponseMock([signalHit]); | ||
|
|
@@ -444,6 +482,9 @@ describe('enrichSignalThreatMatches', () => { | |
| }, | ||
| other: 'other_1', | ||
| type: 'type_1', | ||
| event: { | ||
| category: 'malware', | ||
| }, | ||
| }, | ||
| ]); | ||
| }); | ||
|
|
@@ -477,7 +518,11 @@ describe('enrichSignalThreatMatches', () => { | |
|
|
||
| it('preserves an existing threat.indicator object on signals', async () => { | ||
| const signalHit = getSignalHitMock({ | ||
| _source: { '@timestamp': 'mocked', threat: { indicator: { existing: 'indicator' } } }, | ||
| _source: { | ||
| '@timestamp': 'mocked', | ||
| event: { category: 'virus' }, | ||
| threat: { indicator: { existing: 'indicator' } }, | ||
| }, | ||
| matched_queries: [matchedQuery], | ||
| }); | ||
| const signals = getSignalsResponseMock([signalHit]); | ||
|
|
@@ -502,6 +547,9 @@ describe('enrichSignalThreatMatches', () => { | |
| }, | ||
| other: 'other_1', | ||
| type: 'type_1', | ||
| event: { | ||
| category: 'malware', | ||
| }, | ||
| }, | ||
| ]); | ||
| }); | ||
|
|
@@ -573,12 +621,14 @@ describe('enrichSignalThreatMatches', () => { | |
| getThreatListItemMock({ | ||
| _id: '123', | ||
| _source: { | ||
| event: { category: 'threat' }, | ||
| threat: { indicator: { domain: 'domain_1', other: 'other_1', type: 'type_1' } }, | ||
| }, | ||
| }), | ||
| getThreatListItemMock({ | ||
| _id: '456', | ||
| _source: { | ||
| event: { category: 'bad' }, | ||
| threat: { indicator: { domain: 'domain_2', other: 'other_2', type: 'type_2' } }, | ||
| }, | ||
| }), | ||
|
|
@@ -622,6 +672,9 @@ describe('enrichSignalThreatMatches', () => { | |
| field: 'event.field', | ||
| type: 'type_1', | ||
| }, | ||
| event: { | ||
| category: 'threat', | ||
| }, | ||
| other: 'other_1', | ||
| type: 'type_1', | ||
| }, | ||
|
|
@@ -634,6 +687,9 @@ describe('enrichSignalThreatMatches', () => { | |
| field: 'event.other', | ||
| type: 'type_2', | ||
| }, | ||
| event: { | ||
| category: 'bad', | ||
| }, | ||
| other: 'other_2', | ||
| type: 'type_2', | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -57,9 +57,11 @@ export const buildMatchedIndicator = ({ | |
| } | ||
| const atomic = get(matchedThreat?._source, query.value) as unknown; | ||
| const type = get(indicator, 'type') as unknown; | ||
| const event = get(matchedThreat?._source, 'event') as unknown; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 this logic is correct, it's just the mappings that are off. |
||
|
|
||
| return { | ||
| ...indicator, | ||
| event, | ||
| matched: { atomic, field: query.field, id: query.id, index: query.index, type }, | ||
| }; | ||
| }); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this file is just currently "ECS event mappings," what do you think about using
ecsMapping.mappings.properties.eventinstead of this new file? I expect we'll want these indicator mappings to be in sync with the latest from ECS, so that might be the best way to accomplish this.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
excellent point!