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
[TIP] add field existence check to the painless script #144344
Conversation
@@ -40,6 +40,7 @@ const mappingsArray: Mappings = [ | |||
RawIndicatorFieldId.FileImphash, | |||
RawIndicatorFieldId.FilePehash, | |||
RawIndicatorFieldId.FileVhash, | |||
RawIndicatorFieldId.FileTelfhash, |
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.
@@ -56,12 +56,25 @@ export enum RawIndicatorFieldId { | |||
* (reverse of https://github.com/elastic/kibana/blob/main/x-pack/plugins/security_solution/common/cti/constants.ts#L35) | |||
*/ | |||
export const IndicatorFieldEventEnrichmentMap: { [id: string]: string[] } = { | |||
[RawIndicatorFieldId.FileSha256]: ['file.hash.sha256'], |
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.
this fixes an unrelated bug: happens when the grid is trying to display the investigate in timeline button, the data grid crashes.
This bug was hidden behind the one the PR is trying to fix.
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.
Are we sure that this fixes it for good? What if there is no threat.indicator.file.hash.*
field on the document. See for example https://github.com/elastic/seceng/issues/4768#issuecomment-1303165947 , their documents have the prefix threatintel.*
instead of threat.*
therefore neither of these mappings will work. But I believe we should still handle this gracefully and don't render the Investigate In Timeline action if it is not supported
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.
I also think this is a good candidate for 8.5 backporting
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.
I think it all depends on how we handle the original bug: if we show the value in the grid with a -
for example (as you suggested earlier) then this might break. If we don't show the entry in the grid this should be good, as this list matches the list we use in the painless script.
Once we figure out the original bug, I can update this piece of code as well
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.
I added a bit more safety to the use_investigate_in_timeline
hook to avoid issues when a new hash is added to one list and not added to another. Ideally, we let the type checker do that and do not rely on syncing two lists manually
x-pack/plugins/threat_intelligence/cypress/e2e/indicators.cy.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/threat_intelligence/cypress/e2e/indicators.cy.ts
Outdated
Show resolved
Hide resolved
@maxcold I pushed a commit with the code I have implemented. These are the steps I'm using to debug things:
Notes: |
return {} as unknown as UseInvestigateInTimelineValue; | ||
} | ||
|
||
const dataProviders: DataProvider[] = [...IndicatorFieldEventEnrichmentMap[key], key].map( |
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.
I believe this bug shows that we should be more strict with the types as we rely on a very specific set of fields for this feature
FileSSDeep = 'threat.indicator.file.hash.ssdeep', | ||
FileTlsh = 'threat.indicator.file.hash.tlsh', | ||
FileImpfuzzy = 'threat.indicator.file.hash.impfuzzy', | ||
FileImphash = 'threat.indicator.file.hash.imphash', | ||
FilePehash = 'threat.indicator.file.hash.pehash', | ||
FileVhash = 'threat.indicator.file.hash.vhash', |
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.
modified these using this source of truth
[RawIndicatorFieldId.FilePehash]: ['file.pehash'], | ||
[RawIndicatorFieldId.FileVhash]: ['file.vhash'], | ||
[RawIndicatorFieldId.FileTelfhash]: ['file.elf.telfhash'], | ||
[RawIndicatorFieldId.FileSSDeep]: ['file.hash.ssdeep'], |
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.
same here, modifying following this
@@ -45,29 +48,68 @@ const THREAT_INTELLIGENCE = '/app/security/threat_intelligence/indicators'; | |||
const URL_WITH_CONTRADICTORY_FILTERS = | |||
'/app/security/threat_intelligence/indicators?indicators=(filterQuery:(language:kuery,query:%27%27),filters:!((%27$state%27:(store:appState),meta:(alias:!n,disabled:!f,index:%27%27,key:threat.indicator.type,negate:!f,params:(query:file),type:phrase),query:(match_phrase:(threat.indicator.type:file))),(%27$state%27:(store:appState),meta:(alias:!n,disabled:!f,index:%27%27,key:threat.indicator.type,negate:!f,params:(query:url),type:phrase),query:(match_phrase:(threat.indicator.type:url)))),timeRange:(from:now/d,to:now/d))'; | |||
|
|||
Cypress.Cy.prototype.onUncaughtException = function () {}; | |||
describe('Invalid Indicators', () => { |
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.
this section tests that the table shows up even with missing fields. The following logic is applied:
- test with all fields present
- test with missing
sha256
- test with missing
sha256
andmd5
- continue removing fields until there are none left
The UI Indicator name column should display the proper value for the present fields.
If no fields are present, the Indicator name column shows -
. and the investigate in timeline button is not rendered
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.
added more tests for the following:
- missing
threat
field entirely - missing
type
field - missing
indicator
field
I think this is overkill but we should be safe
}); | ||
|
||
describe('verify the grid loads even with missing fields', () => { | ||
describe('verify the grid loads even with missing mappings and missing fields', () => { |
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.
same tests as above but this time with a missing mappings.json
file. Not sure these tests are really useful though...
@@ -63,7 +62,7 @@ const fieldTypeCheck = (type: string) => | |||
* Generates Painless condition checking if given `field` has value | |||
*/ | |||
const fieldValueCheck = (field: string) => | |||
`if (doc['${field}'].size()!=0 && doc['${field}'].value!=null)`; | |||
`if (doc.containsKey('${field}') && !doc['${field}'].empty && doc['${field}'].size()!=0 && doc['${field}'].value!=null)`; |
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.
following this documentation for missing keys and missing values
- fix fields in RawIndicatorFieldId (for investigate in timeline hook crash) - fix logic to check if a field exist in the painless script - add more e2e to test with missing fields and also missing mappings file
7c87fe0
to
dc75859
Compare
@@ -56,12 +56,13 @@ const mappingsArray: Mappings = [ | |||
* Generates Painless condition checking if given `type` is matched | |||
*/ | |||
const fieldTypeCheck = (type: string) => | |||
`if (doc['threat.indicator.type'].value != null && doc['threat.indicator.type'].value.toLowerCase()=='${type.toLowerCase()}')`; | |||
`if (doc.containsKey('threat.indicator.type') && !doc['threat.indicator.type'].empty && doc['threat.indicator.type'].size()!=0 && doc['threat.indicator.type'].value!=null && doc['threat.indicator.type'].value.toLowerCase()=='${type.toLowerCase()}')`; |
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.
The changes looks good to me! |
💚 Build Succeeded
Metrics [docs]Async chunks
Unknown metric groupsESLint disabled in files
ESLint disabled line counts
Total ESLint disabled count
History
To update your PR or re-run it, just comment with: |
Pinging @elastic/security-solution (Team: SecuritySolution) |
Fixes https://github.com/elastic/security-team/issues/5296
Summary
The painless script that generates
threat.indicator.name
runtime field was missing the check for field existence. Specificially it impacted the cases where there is a file type indicator document withoutthreat.indicator.file.hash.sha256
as it was being checked first for file type IoCs. The app crashes in such cases and/or behaves weirdly depending on the data grid action used