Skip to content

Commit

Permalink
Added backslashes handling to drilldown enrichment (#34811)
Browse files Browse the repository at this point in the history
* Added backslashes handling to drilldown enrichment

* Added comment + pre commit fixes

* Fixed unit test

* Added a test

* fix test

* Handled splunk variables that were surrounded by quotation marks in the original query

* precommit fixes

* Added RN file

* Fixed Typo

* Removed redundant logs

* Removed unnecessary logs

* Delete unnecessary variable

* delete RN file

* Update the RN files
  • Loading branch information
ShacharKidor committed Jun 20, 2024
1 parent fa56ca8 commit 108afed
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 15 deletions.
23 changes: 20 additions & 3 deletions Packs/SplunkPy/Integrations/SplunkPy/SplunkPy.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
IDENTITY_ENRICHMENT: 'successful_identity_enrichment'
}
COMMENT_MIRRORED_FROM_XSOAR = 'Mirrored from Cortex XSOAR'
USER_RELATED_FIELDS = ['user', 'src_user']

# =========== Not Missing Events Mechanism Globals ===========
CUSTOM_ID = 'custom_id'
Expand Down Expand Up @@ -972,14 +973,30 @@ def build_drilldown_search(notable_data, search, raw_dict, is_query_name=False):
if not is_query_name:
demisto.error(f'Failed building drilldown search query. Field {raw_field} was not found in the notable.')
return ""

if prefix:
replacement = get_fields_query_part(notable_data, prefix, [field], raw_dict)
if field in USER_RELATED_FIELDS:
replacement = get_fields_query_part(notable_data, prefix, [field], raw_dict, add_backslash=True)
else:
replacement = get_fields_query_part(notable_data, prefix, [field], raw_dict)

elif field in USER_RELATED_FIELDS:
# User fields usually contains backslashes - to pass a literal backslash in an argument to Splunk we must escape
# the backslash by using the double-slash ( \\ ) string
replacement = replacement.replace('\\', '\\\\')
replacement = f""""{replacement.strip('"')}\""""

end = match.start()
searchable_search.extend((search[start:end], str(replacement)))
start = match.end()
searchable_search.append(search[start:]) # Handling the tail of the query

return ''.join(searchable_search)
parsed_query = ''.join(searchable_search)
# Avoiding double quotes in splunk variables that were surrounded by quotation marks in the original query (ex: '"$user|s"')
parsed_query = parsed_query.replace('""', '"')
demisto.debug(f"Parsed query is: {parsed_query}")

return parsed_query


def get_drilldown_timeframe(notable_data, raw) -> tuple[str, str]:
Expand Down Expand Up @@ -1146,7 +1163,7 @@ def identity_enrichment(service: client.Service, notable_data, num_enrichment_ev
if users := get_fields_query_part(
notable_data=notable_data,
prefix="identity",
fields=["user", "src_user"],
fields=USER_RELATED_FIELDS,
add_backslash=True,
):
tables = argToList(demisto.params().get('identity_enrich_lookup_tables', DEFAULT_IDENTITY_ENRICH_TABLE))
Expand Down
31 changes: 20 additions & 11 deletions Packs/SplunkPy/Integrations/SplunkPy/SplunkPy_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1100,24 +1100,30 @@ def test_get_notable_field_and_value(raw_field, notable_data, expected_field, ex
assert value == expected_value


@pytest.mark.parametrize('notable_data, search, raw, expected_search', [
({'a': '1', '_raw': 'c=3'}, 'search a=$a|s$ c=$c$ suffix', {'c': '3'}, 'search a="1" c="3" suffix'),
({'a': ['1', '2'], 'b': '3'}, 'search a=$a|s$ b=$b|s$ suffix', {}, 'search (a="1" OR a="2") b="3" suffix'),
({'a': '1', '_raw': 'b=3', 'event_id': '123'}, 'search a=$a|s$ c=$c$ suffix', {'b': '3'}, ''),
({"signature": "Backdoor.test"}, "View related '$signature$' events for $dest$", {"dest": "ACME-test-005"},
@pytest.mark.parametrize('notable_data, search, raw, is_query_name, expected_search', [
({'a': '1', '_raw': 'c=3'}, 'search a=$a|s$ c=$c$ suffix', {'c': '3'}, False, 'search a="1" c="3" suffix'),
({'a': ['1', '2'], 'b': '3'}, 'search a=$a|s$ b=$b|s$ suffix', {}, False, 'search (a="1" OR a="2") b="3" suffix'),
({'a': '1', '_raw': 'b=3', 'event_id': '123'}, 'search a=$a|s$ c=$c$ suffix', {'b': '3'}, False, ''),
({"signature": "Backdoor.test"}, "View related '$signature$' events for $dest$", {"dest": "ACME-test-005"}, True,
"View related 'Backdoor.test' events for ACME-test-005"),
({}, 'View all wineventlogs involving user="$user$"', {'user': "test"},
({}, 'View all wineventlogs involving user="$user$"', {'user': "test"}, True,
'View all wineventlogs involving user="test"'),
({}, 'Test query name', {}, 'Test query name')
({}, 'Test query name', {}, True, 'Test query name'),
({'user': 'test\crusher'}, 'index="test" | where user = $user|s$', {}, False,
'index="test" | where user = "test\\\\crusher"'),
({'user': 'test\crusher'}, 'index="test" | where user = "$user|s$"', {}, False,
'index="test" | where user = "test\\\\crusher"')
], ids=[
"search query fields in notables data and raw data",
"search query fields in notable data more than one value",
"search query fields don't exist in notable data and raw data",
"query name fields in notables data and raw data",
"query name fields in raw data",
"query name without fields to replace"
"query name without fields to replace",
"search query with a user field that contains a backslash",
"search query with a user field that is surrounded by quotation marks and contains a backslash"
])
def test_build_drilldown_search(notable_data, search, raw, expected_search, mocker):
def test_build_drilldown_search(notable_data, search, raw, is_query_name, expected_search, mocker):
"""
Scenario: When building the drilldown search query, we replace every field in between "$" sign with its
corresponding query part (key & value).
Expand All @@ -1129,6 +1135,8 @@ def test_build_drilldown_search(notable_data, search, raw, expected_search, mock
- A raw query name with fields both in the notable's data and in the notable's raw data
- A raw query name with fields in the notable's raw data
- A raw query name without any fields to replace.
- A raw query search with a user field that contains a backslash
- A raw query search with a user field that is surrounded by quotation marks and contains a backslash
When:
Expand All @@ -1138,7 +1146,8 @@ def test_build_drilldown_search(notable_data, search, raw, expected_search, mock
- Return the expected result
"""
mocker.patch.object(demisto, 'error')
assert splunk.build_drilldown_search(notable_data, search, raw) == expected_search
parsed_query = splunk.build_drilldown_search(notable_data, search, raw, is_query_name)
assert parsed_query == expected_search


@pytest.mark.parametrize('notable_data, prefix, fields, query_part', [
Expand Down Expand Up @@ -1519,7 +1528,7 @@ def test_drilldown_enrichment_get_timeframe(mocker, notable_data, expected_call_
[("View all login attempts by system 'test_src'",
'| from datamodel:"Authentication"."Authentication" | search src="\'test_src\'"'),
('View all test involving user="\'test_user\'"',
'search index="test"\n| where user = \'test_user\'')]),
'search index="test"\n| where user = "\'test_user\'"')]),
], ids=[
"A notable data with one drilldown search enrichment",
"A notable data with multiple (two) drilldown searches to enrich"
Expand Down
5 changes: 5 additions & 0 deletions Packs/SplunkPy/ReleaseNotes/3_1_31.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#### Integrations

##### SplunkPy

- Fixed an issue where drilldown search enrichment associated with Splunk notables didn't return results for queries that included user data.
2 changes: 1 addition & 1 deletion Packs/SplunkPy/pack_metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "Splunk",
"description": "Run queries on Splunk servers.",
"support": "xsoar",
"currentVersion": "3.1.30",
"currentVersion": "3.1.31",
"author": "Cortex XSOAR",
"url": "https://www.paloaltonetworks.com/cortex",
"email": "",
Expand Down

0 comments on commit 108afed

Please sign in to comment.