Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sigma/backends/splunk/spl2.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class SplunkSPL2Backend(TextQueryBackend):

precedence: ClassVar[Tuple[ConditionItem, ConditionItem, ConditionItem]] = (
ConditionNOT,
ConditionOR,
ConditionAND,
ConditionOR,
)
group_expression: ClassVar[str] = "({expr})"

Expand Down
2 changes: 1 addition & 1 deletion sigma/backends/splunk/splunk.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ class SplunkBackend(TextQueryBackend):

precedence: ClassVar[Tuple[ConditionItem, ConditionItem, ConditionItem]] = (
ConditionNOT,
ConditionOR,
ConditionAND,
ConditionOR,
)
group_expression: ClassVar[str] = "({expr})"

Expand Down
38 changes: 31 additions & 7 deletions tests/test_backend_splunk.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def test_splunk_and_or_expression(splunk_backend: SplunkBackend):
"""
)
assert splunk_backend.convert(rule) == [
'fieldA IN ("valueA1", "valueA2") fieldB IN ("valueB1", "valueB2")'
'(fieldA IN ("valueA1", "valueA2")) (fieldB IN ("valueB1", "valueB2"))'
]


Expand All @@ -101,7 +101,31 @@ def test_splunk_or_and_expression(splunk_backend: SplunkBackend):
"""
)
assert splunk_backend.convert(rule) == [
'(fieldA="valueA1" fieldB="valueB1") OR (fieldA="valueA2" fieldB="valueB2")'
'fieldA="valueA1" fieldB="valueB1" OR fieldA="valueA2" fieldB="valueB2"'
]


def test_splunk_or_nested_in_and_expression(splunk_backend: SplunkBackend):
"""An OR nested inside an AND must be parenthesized: implicit AND (juxtaposition)
binds tighter than OR in SPL, so an ungrouped OR would silently widen the query."""
rule = SigmaCollection.from_yaml(
"""
title: Test
status: test
logsource:
category: test_category
product: test_product
detection:
selection_img:
- Image|endswith: '\\net.exe'
- OriginalFileName: 'net.exe'
selection_cli:
CommandLine|contains: ' localgroup'
condition: selection_img and selection_cli
"""
)
assert splunk_backend.convert(rule) == [
'(Image="*\\\\net.exe" OR OriginalFileName="net.exe") CommandLine="* localgroup*"'
]


Expand Down Expand Up @@ -195,7 +219,7 @@ def test_splunk_regex_query_implicit_or(splunk_backend: SplunkBackend):
)
)
== [
'\n| rex field=fieldA "(?<fieldAMatch>foo.*bar)"\n| eval fieldACondition=if(isnotnull(fieldAMatch), "true", "false")\n| rex field=fieldA "(?<fieldAMatch2>boo.*foo)"\n| eval fieldACondition2=if(isnotnull(fieldAMatch2), "true", "false")\n| search fieldACondition="true" OR fieldACondition2="true" fieldB="foo" fieldC="bar"'
'\n| rex field=fieldA "(?<fieldAMatch>foo.*bar)"\n| eval fieldACondition=if(isnotnull(fieldAMatch), "true", "false")\n| rex field=fieldA "(?<fieldAMatch2>boo.*foo)"\n| eval fieldACondition2=if(isnotnull(fieldAMatch2), "true", "false")\n| search (fieldACondition="true" OR fieldACondition2="true") fieldB="foo" fieldC="bar"'
]
)

Expand Down Expand Up @@ -302,7 +326,7 @@ def test_splunk_regex_query_explicit_or_with_add_condition():
)

assert splunk_backend.convert(collection) == [
'index="test" source="test"\n| rex field=CommandLine "(?<CommandLineMatch>suspicious_command)"\n| eval CommandLineCondition=if(isnotnull(CommandLineMatch), "true", "false")\n| rex field=Image "(?<ImageMatch>suspicious_command)"\n| eval ImageCondition=if(isnotnull(ImageMatch), "true", "false")\n| search (EventID=4688 CommandLineCondition="true") OR ImageCondition="true"'
'index="test" source="test"\n| rex field=CommandLine "(?<CommandLineMatch>suspicious_command)"\n| eval CommandLineCondition=if(isnotnull(CommandLineMatch), "true", "false")\n| rex field=Image "(?<ImageMatch>suspicious_command)"\n| eval ImageCondition=if(isnotnull(ImageMatch), "true", "false")\n| search (EventID=4688 CommandLineCondition="true" OR ImageCondition="true")'
]


Expand Down Expand Up @@ -409,7 +433,7 @@ def test_splunk_cidr_or(splunk_backend: SplunkBackend):
"""
)
)
== ['fieldA="192.168.0.0/16" OR fieldA="10.0.0.0/8" fieldB="foo" fieldC="bar"']
== ['(fieldA="192.168.0.0/16" OR fieldA="10.0.0.0/8") fieldB="foo" fieldC="bar"']
)


Expand Down Expand Up @@ -923,11 +947,11 @@ def test_splunk_data_model_process_creation_with_or_regex():
result = splunk_backend.convert(SigmaCollection.from_yaml(rule), "data_model")
assert result == [
"""| tstats summariesonly=false allow_old_summaries=true fillnull_value="null" count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where
Processes.parent_process_path="*explorer.exe" Processes.process="*test_value*" OR processCondition="true" by Processes.process Processes.dest Processes.process_current_directory Processes.process_path Processes.process_integrity_level Processes.original_file_name Processes.parent_process
Processes.parent_process_path="*explorer.exe" (Processes.process="*test_value*" OR processCondition="true") by Processes.process Processes.dest Processes.process_current_directory Processes.process_path Processes.process_integrity_level Processes.original_file_name Processes.parent_process
Processes.parent_process_path Processes.parent_process_guid Processes.parent_process_id Processes.process_guid Processes.process_id Processes.user
| rex field=Processes.process "(?<processMatch>foo.*bar)"
| eval processCondition=if(isnotnull(processMatch), "true", "false")
| search Processes.parent_process_path="*explorer.exe" Processes.process="*test_value*" OR processCondition="true"
| search Processes.parent_process_path="*explorer.exe" (Processes.process="*test_value*" OR processCondition="true")
| `drop_dm_object_name(Processes)`
| convert timeformat="%Y-%m-%dT%H:%M:%S" ctime(firstTime)
| convert timeformat="%Y-%m-%dT%H:%M:%S" ctime(lastTime)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_backend_splunk_spl2.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def test_spl2_and_or_expression(spl2_backend: SplunkSPL2Backend):
"""
)
assert spl2_backend.convert(rule) == [
'FROM main WHERE fieldA IN ("valueA1", "valueA2") AND fieldB IN ("valueB1", "valueB2")'
'FROM main WHERE (fieldA IN ("valueA1", "valueA2")) AND (fieldB IN ("valueB1", "valueB2"))'
]


Expand All @@ -92,7 +92,7 @@ def test_spl2_or_and_expression(spl2_backend: SplunkSPL2Backend):
"""
)
assert spl2_backend.convert(rule) == [
'FROM main WHERE (fieldA="valueA1" AND fieldB="valueB1") OR (fieldA="valueA2" AND fieldB="valueB2")'
'FROM main WHERE fieldA="valueA1" AND fieldB="valueB1" OR fieldA="valueA2" AND fieldB="valueB2"'
]


Expand Down
4 changes: 2 additions & 2 deletions tests/test_splunk_pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ def test_splunk_windows_pipeline_simple(service, source):
)
)
== [
"source IN ("
"(source IN ("
+ ", ".join((f'"WinEventLog:{source_item}"' for source_item in source))
+ ') EventCode=123 field="value"'
+ ')) EventCode=123 field="value"'
]
)

Expand Down
Loading