Skip to content

Commit

Permalink
Optionally allow special characters in cased startswith, endswith, an…
Browse files Browse the repository at this point in the history
…d contains expressions
  • Loading branch information
thomaspatzke committed Oct 14, 2024
1 parent 20bc3f2 commit a81d690
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 5 deletions.
20 changes: 15 additions & 5 deletions sigma/conversion/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -842,8 +842,11 @@ class variables. If this is not sufficient, the respective methods can be implem
# Case sensitive string matching operators similar to standard string matching. If not provided,
# case_sensitive_match_expression is used.
case_sensitive_startswith_expression: ClassVar[Optional[str]] = None
case_sensitive_startswith_expression_allow_special: ClassVar[bool] = False
case_sensitive_endswith_expression: ClassVar[Optional[str]] = None
case_sensitive_endswith_expression_allow_special: ClassVar[bool] = False
case_sensitive_contains_expression: ClassVar[Optional[str]] = None
case_sensitive_contains_expression_allow_special: ClassVar[bool] = False

# CIDR expressions: define CIDR matching if backend has native support. Else pySigma expands
# CIDR values into string wildcard matches.
Expand Down Expand Up @@ -1369,9 +1372,10 @@ def convert_condition_field_eq_val_str_case_sensitive(
self.case_sensitive_startswith_expression
is not None # 'startswith' operator is defined in backend
and cond.value.endswith(SpecialChars.WILDCARD_MULTI) # String ends with wildcard
and not cond.value[
:-1
].contains_special() # Remainder of string doesn't contains special characters
and (
self.case_sensitive_startswith_expression_allow_special
or not cond.value[:-1].contains_special()
) # Remainder of string doesn't contains special characters or it's allowed
):
expr = (
self.case_sensitive_startswith_expression
Expand All @@ -1380,15 +1384,21 @@ def convert_condition_field_eq_val_str_case_sensitive(
elif ( # Same as above but for 'endswith' operator: string starts with wildcard and doesn't contains further special characters
self.case_sensitive_endswith_expression is not None
and cond.value.startswith(SpecialChars.WILDCARD_MULTI)
and not cond.value[1:].contains_special()
and (
self.case_sensitive_endswith_expression_allow_special
or not cond.value[1:].contains_special()
)
):
expr = self.case_sensitive_endswith_expression
value = cond.value[1:]
elif ( # contains: string starts and ends with wildcard
self.case_sensitive_contains_expression is not None
and cond.value.startswith(SpecialChars.WILDCARD_MULTI)
and cond.value.endswith(SpecialChars.WILDCARD_MULTI)
and not cond.value[1:-1].contains_special()
and (
self.case_sensitive_contains_expression_allow_special
or not cond.value[1:-1].contains_special()
)
):
expr = self.case_sensitive_contains_expression
value = cond.value[1:-1]
Expand Down
129 changes: 129 additions & 0 deletions tests/test_conversion_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,49 @@ def test_convert_value_str_startswith_further_wildcard_allowed(test_backend, mon
)


def test_convert_value_str_startswith_cased_further_wildcard(test_backend):
assert (
test_backend.convert(
SigmaCollection.from_yaml(
"""
title: Test
status: test
logsource:
category: test_category
product: test_product
detection:
sel:
"field|startswith|cased": "va*lue"
condition: sel
"""
)
)
== ['field casematch "va*lue*"']
)


def test_convert_value_str_startswith_cased_further_wildcard_allowed(test_backend, monkeypatch):
monkeypatch.setattr(test_backend, "case_sensitive_startswith_expression_allow_special", True)
assert (
test_backend.convert(
SigmaCollection.from_yaml(
"""
title: Test
status: test
logsource:
category: test_category
product: test_product
detection:
sel:
"field|startswith|cased": "va*lue"
condition: sel
"""
)
)
== ['field startswith_cased "va*lue"']
)


def test_convert_value_str_startswith_expression_not_defined(test_backend, monkeypatch):
monkeypatch.setattr(test_backend, "startswith_expression", None)
assert (
Expand Down Expand Up @@ -462,6 +505,49 @@ def test_convert_value_str_endswith_further_wildcard_allowed(test_backend, monke
)


def test_convert_value_str_endswith_cased_further_wildcard(test_backend):
assert (
test_backend.convert(
SigmaCollection.from_yaml(
"""
title: Test
status: test
logsource:
category: test_category
product: test_product
detection:
sel:
"field|endswith|cased": "va*lue"
condition: sel
"""
)
)
== ['field casematch "*va*lue"']
)


def test_convert_value_str_endswith_cased_further_wildcard_allowed(test_backend, monkeypatch):
monkeypatch.setattr(test_backend, "case_sensitive_endswith_expression_allow_special", True)
assert (
test_backend.convert(
SigmaCollection.from_yaml(
"""
title: Test
status: test
logsource:
category: test_category
product: test_product
detection:
sel:
"field|endswith|cased": "va*lue"
condition: sel
"""
)
)
== ['field endswith_cased "va*lue"']
)


def test_convert_value_str_endswith_expression_not_defined(test_backend, monkeypatch):
monkeypatch.setattr(test_backend, "endswith_expression", None)
assert (
Expand Down Expand Up @@ -571,6 +657,49 @@ def test_convert_value_str_contains_further_wildcard_allowed(test_backend, monke
)


def test_convert_value_str_contains_cased_further_wildcard(test_backend):
assert (
test_backend.convert(
SigmaCollection.from_yaml(
"""
title: Test
status: test
logsource:
category: test_category
product: test_product
detection:
sel:
"field|contains|cased": "va*lue"
condition: sel
"""
)
)
== ['field casematch "*va*lue*"']
)


def test_convert_value_str_contains_cased_further_wildcard_allowed(test_backend, monkeypatch):
monkeypatch.setattr(test_backend, "case_sensitive_contains_expression_allow_special", True)
assert (
test_backend.convert(
SigmaCollection.from_yaml(
"""
title: Test
status: test
logsource:
category: test_category
product: test_product
detection:
sel:
"field|contains|cased": "va*lue"
condition: sel
"""
)
)
== ['field contains_cased "va*lue"']
)


def test_convert_value_str_wildcard_to_regex(test_backend, monkeypatch):
monkeypatch.setattr(test_backend, "wildcard_match_expression", '{field} match "{regex}"')
assert (
Expand Down

0 comments on commit a81d690

Please sign in to comment.