Skip to content
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

Merged
merged 1 commit into from Nov 8, 2022

Conversation

maxcold
Copy link
Contributor

@maxcold maxcold commented Nov 1, 2022

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 without threat.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

@maxcold maxcold added release_note:skip Skip the PR/issue when compiling release notes backport:skip This commit does not require backporting Team: Protections Experience v8.6.0 labels Nov 1, 2022
@maxcold maxcold requested a review from a team as a code owner November 1, 2022 17:35
@@ -40,6 +40,7 @@ const mappingsArray: Mappings = [
RawIndicatorFieldId.FileImphash,
RawIndicatorFieldId.FilePehash,
RawIndicatorFieldId.FileVhash,
RawIndicatorFieldId.FileTelfhash,
Copy link
Contributor

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'],
Copy link
Contributor

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.

Copy link
Contributor Author

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

Copy link
Contributor Author

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

Copy link
Contributor

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

Copy link
Contributor Author

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

@PhilippeOberti
Copy link
Contributor

@maxcold I pushed a commit with the code I have implemented. These are the steps I'm using to debug things:

  • run cypress using yarn cypress:open-as-ci
  • remove/add values here and see the change reflect in the indicators table in the UI

Notes:
You might want to run ES (yarn es snapshot --license trial) and kibana (yarn start --no-base-path) as you run Cypress, to help on reload. I found that without running kibana the UI isn't refreshing properly after making code changes in the public folder. Also when you change the code in the server folder, you have to restart Cypress completely (yarn cypress:open-as-ci).

return {} as unknown as UseInvestigateInTimelineValue;
}

const dataProviders: DataProvider[] = [...IndicatorFieldEventEnrichmentMap[key], key].map(
Copy link
Contributor Author

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

Comment on lines +35 to +40
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',
Copy link
Contributor

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'],
Copy link
Contributor

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', () => {
Copy link
Contributor

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 and md5
  • 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

Copy link
Contributor

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', () => {
Copy link
Contributor

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)`;
Copy link
Contributor

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
@@ -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()}')`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got this change from @maxcold comment and work here

@maxcold
Copy link
Contributor Author

maxcold commented Nov 8, 2022

The changes looks good to me!

@kibana-ci
Copy link
Collaborator

💚 Build Succeeded

Metrics [docs]

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
threatIntelligence 43.1KB 43.6KB +450.0B
Unknown metric groups

ESLint disabled in files

id before after diff
osquery 1 2 +1

ESLint disabled line counts

id before after diff
enterpriseSearch 19 21 +2
fleet 59 65 +6
osquery 108 113 +5
securitySolution 440 446 +6
total +19

Total ESLint disabled count

id before after diff
enterpriseSearch 20 22 +2
fleet 67 73 +6
osquery 109 115 +6
securitySolution 517 523 +6
total +20

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@PhilippeOberti PhilippeOberti merged commit 0082424 into main Nov 8, 2022
@PhilippeOberti PhilippeOberti deleted the tip-add-safety-check-to-painless branch November 8, 2022 16:51
@maxcold maxcold added release_note:fix Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. and removed release_note:skip Skip the PR/issue when compiling release notes labels Nov 10, 2022
@elasticmachine
Copy link
Contributor

Pinging @elastic/security-solution (Team: SecuritySolution)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting release_note:fix Team: Protections Experience Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. v8.6.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants