@@ -41,41 +41,53 @@ class SplunkDeferredORRegularExpression(DeferredTextQueryExpression):
4141 }
4242
4343 def __init__ (self , state , field , arg ) -> None :
44- SplunkDeferredORRegularExpression .add_field (field )
45- index_suffix = SplunkDeferredORRegularExpression .get_index_suffix (field )
46- self .template = (
47- 'rex field={field} "(?<{field}Match'
48- + index_suffix
49- + '>{value})"\n | eval {field}Condition'
50- + index_suffix
51- + "=if(isnotnull({field}Match"
52- + index_suffix
53- + '), "true", "false")'
44+ self .add_field (field )
45+ field_condition = self .get_field_condition (field )
46+ field_match = self .get_field_match (field )
47+ self .template = 'rex field={{field}} "(?<{field_match}>{{value}})"\n | eval {field_condition}=if(isnotnull({field_match}), "true", "false")' .format (
48+ field_match = field_match , field_condition = field_condition
5449 )
5550 return super ().__init__ (state , field , arg )
5651
52+ @staticmethod
53+ def clean_field (field ):
54+ # splunk does not allow dots in regex group, so we need to clean variables
55+ return re .sub (".*\\ ." , "" , field )
56+
5757 @classmethod
5858 def add_field (cls , field ):
5959 cls .field_counts [field ] = (
6060 cls .field_counts .get (field , 0 ) + 1
6161 ) # increment the field count
6262
6363 @classmethod
64- def get_index_suffix (cls , field ):
65-
66- index_suffix = cls .field_counts .get (field , 0 )
64+ def get_field_suffix (cls , field ):
65+ index_suffix = cls .field_counts .get (field , "" )
6766 if index_suffix == 1 :
68- # return nothing for the first field use
69- return ""
70- return str (index_suffix )
67+ index_suffix = ""
68+ return index_suffix
69+
70+ @classmethod
71+ def construct_field_variable (cls , field , variable ):
72+ cleaned_field = cls .clean_field (field )
73+ index_suffix = cls .get_field_suffix (field )
74+ return f"{ cleaned_field } { variable } { index_suffix } "
75+
76+ @classmethod
77+ def get_field_match (cls , field ):
78+ return cls .construct_field_variable (field , "Match" )
79+
80+ @classmethod
81+ def get_field_condition (cls , field ):
82+ return cls .construct_field_variable (field , "Condition" )
7183
7284 @classmethod
7385 def reset (cls ):
7486 cls .field_counts = {}
7587
7688
77- class SplunkDeferredCIDRExpression (DeferredTextQueryExpression ):
78- template = ' where {op}cidrmatch("{value}", {field})'
89+ class SplunkDeferredFieldRefExpression (DeferredTextQueryExpression ):
90+ template = " where {op}'{field}'='{value}'"
7991 operators = {
8092 True : "NOT " ,
8193 False : "" ,
@@ -107,6 +119,7 @@ class SplunkBackend(TextQueryBackend):
107119 )
108120 group_expression : ClassVar [str ] = "({expr})"
109121
122+ bool_values = {True : "true" , False : "false" }
110123 or_token : ClassVar [str ] = "OR"
111124 and_token : ClassVar [str ] = " "
112125 not_token : ClassVar [str ] = "NOT"
@@ -125,7 +138,7 @@ class SplunkBackend(TextQueryBackend):
125138 re_escape_char : ClassVar [str ] = "\\ "
126139 re_escape : ClassVar [Tuple [str ]] = ('"' ,)
127140
128- cidr_expression : ClassVar [str ] = "{value}"
141+ cidr_expression : ClassVar [str ] = '{field}= "{value}"'
129142
130143 compare_op_expression : ClassVar [str ] = "{field}{operator}{value}"
131144 compare_operators : ClassVar [Dict [SigmaCompareExpression .CompareOperators , str ]] = {
@@ -135,6 +148,7 @@ class SplunkBackend(TextQueryBackend):
135148 SigmaCompareExpression .CompareOperators .GTE : ">=" ,
136149 }
137150
151+ field_equals_field_expression : ClassVar [str ] = "{field2}"
138152 field_null_expression : ClassVar [str ] = "NOT {field}=*"
139153
140154 convert_or_as_in : ClassVar [bool ] = True
@@ -248,9 +262,7 @@ def convert_condition_field_eq_val_re(
248262 ).postprocess (None , cond )
249263
250264 cond_true = ConditionFieldEqualsValueExpression (
251- cond .field
252- + "Condition"
253- + str (SplunkDeferredORRegularExpression .get_index_suffix (cond .field )),
265+ SplunkDeferredORRegularExpression .get_field_condition (cond .field ),
254266 SigmaString ("true" ),
255267 )
256268 # returning fieldX=true
@@ -259,19 +271,19 @@ def convert_condition_field_eq_val_re(
259271 state , cond .field , super ().convert_condition_field_eq_val_re (cond , state )
260272 ).postprocess (None , cond )
261273
262- def convert_condition_field_eq_val_cidr (
274+ def convert_condition_field_eq_field (
263275 self ,
264276 cond : ConditionFieldEqualsValueExpression ,
265277 state : "sigma.conversion.state.ConversionState" ,
266- ) -> SplunkDeferredCIDRExpression :
267- """Defer CIDR network range matching to pipelined where cidrmatch command after main search expression."""
278+ ) -> SplunkDeferredFieldRefExpression :
279+ """Defer FieldRef matching to pipelined with `where` command after main search expression."""
268280 if cond .parent_condition_chain_contains (ConditionOR ):
269281 raise SigmaFeatureNotSupportedByBackendError (
270- "ORing CIDR matching is not yet supported by Splunk backend" ,
282+ "ORing FieldRef matching is not yet supported by Splunk backend" ,
271283 source = cond .source ,
272284 )
273- return SplunkDeferredCIDRExpression (
274- state , cond .field , super ().convert_condition_field_eq_val_cidr (cond , state )
285+ return SplunkDeferredFieldRefExpression (
286+ state , cond .field , super ().convert_condition_field_eq_field (cond , state )
275287 ).postprocess (None , cond )
276288
277289 def finalize_query (
@@ -381,13 +393,11 @@ def finalize_query_data_model(
381393 cim_fields = " " .join (
382394 splunk_sysmon_process_creation_cim_mapping .values ()
383395 )
384-
396+
385397 elif rule .logsource .category == "proxy" :
386398 data_model = "Web"
387399 data_set = "Proxy"
388- cim_fields = " " .join (
389- splunk_web_proxy_cim_mapping .values ()
390- )
400+ cim_fields = " " .join (splunk_web_proxy_cim_mapping .values ())
391401
392402 try :
393403 data_model_set = state .processing_state ["data_model_set" ]
0 commit comments