Repository: SigmaHQ/sigma

Issue:
Duplicated rules generated with elastalert backend
Hi there!

Just discovered some weird behavior... seems the converter generates two elastalert rules (same content, different name, see example below).

Am I doing someting wrong?

Thanks for your efforts!

```
[root@my_machine sigma]# tools/sigmac -t elastalert -c tools/config/generic/sysmon.yml rules/windows/builtin/win_susp_psexec.yml
alert:
- debug
description: detects execution of psexec or paexec with renamed service name, this rule helps to filter out the noise if psexec is used for legit purposes or if attacker uses a different psexec client other than sysinternal one
filter:
- query:
    query_string:
      query: ((EventID:"5145" AND ShareName.keyword:\\*\\IPC$ AND RelativeTargetName.keyword:(*\-stdin OR *\-stdout OR *\-stderr)) AND (NOT (EventID:"5145" AND ShareName.keyword:\\*\\IPC$ AND RelativeTargetName.keyword:PSEXESVC*)))
index: logstash-*
name: c462f537-a1e3-41a6-b5fc-b2c2cef9bf82-Suspicious-PsExec-Execution
priority: 2
realert:
  minutes: 0
type: any

alert:
- debug
description: detects execution of psexec or paexec with renamed service name, this rule helps to filter out the noise if psexec is used for legit purposes or if attacker uses a different psexec client other than sysinternal one
filter:
- query:
    query_string:
      query: ((EventID:"5145" AND ShareName.keyword:\\*\\IPC$ AND RelativeTargetName.keyword:(*\-stdin OR *\-stdout OR *\-stderr)) AND (NOT (EventID:"5145" AND ShareName.keyword:\\*\\IPC$ AND RelativeTargetName.keyword:PSEXESVC*)))
index: logstash-*
name: c462f537-a1e3-41a6-b5fc-b2c2cef9bf82-Suspicious-PsExec-Execution-2
priority: 2
realert:
  minutes: 0
type: any
```




Discussion:
additional info:
[root@my_machine sigma]# git describe --tags
0.19.1-2659-g5ce5465
first investigation : 
https://github.com/SigmaHQ/sigma/blob/28abe889271c55499c3d6431ba5d09def97787aa/tools/sigma/backends/elasticsearch.py#L1237
`sigmaparser.condparsed` get **2** elements even if there is only 1 detection.
Same issue with `kibana` backend
Hi,
Same error with `kibana-ndjson`.
It is not the `for` as the `generate()` is run 2 time  :confused:



Resolving patch:
diff --git a/tools/sigma/backends/elasticsearch.py b/tools/sigma/backends/elasticsearch.py
--- a/tools/sigma/backends/elasticsearch.py
+++ b/tools/sigma/backends/elasticsearch.py
@@ -300,6 +300,7 @@ def generateSubexpressionNode(self, node):
             return result
         else:
             return super().generateSubexpressionNode(node)
+
 class ElasticsearchQuerystringBackendLogRhythm(DeepFieldMappingMixin, ElasticsearchWildcardHandlingMixin, SingleTextQueryBackend):
     """Converts Sigma rule into Lucene query string for LogRhythm. Only searches, no aggregations."""
     identifier = "es-qs-lr"
@@ -365,8 +366,7 @@ def generateSubexpressionNode(self, node):
             return result
         else:
             return super().generateSubexpressionNode(node)
-        
-        
+
 class ElasticsearchEQLBackend(DeepFieldMappingMixin, ElasticsearchWildcardHandlingMixin, SingleTextQueryBackend):
     """Converts Sigma rule into EQL."""
     identifier = "es-eql"
diff --git a/tools/sigma/sigmac.py b/tools/sigma/sigmac.py
--- a/tools/sigma/sigmac.py
+++ b/tools/sigma/sigmac.py
@@ -33,6 +33,7 @@
 from sigma.backends.exceptions import BackendError, NotSupportedError, PartialMatchError, FullMatchError
 from sigma.parser.modifiers import modifiers
 import codecs
+import copy
 
 sys.stdout = codecs.getwriter('utf-8')(sys.stdout.detach())
 
@@ -249,11 +250,9 @@ def main():
             parser = SigmaCollectionParser(f, sigmaconfigs, rulefilter, sigmafile)
             results = parser.generate(backend)
             
-            nb_result = len(list(parser.generate(backend)))
-            if nb_result > 1 :
-                inc_filenane = 0
-            else:
-                inc_filenane = None
+            nb_result = len(list(copy.deepcopy(results)))
+            inc_filenane = None if nb_result < 2 else 0
+
             
             newline_separator = '\0' if cmdargs.print0 else '\n'
             for result in results:
@@ -275,6 +274,25 @@ def main():
                         print("Failed to open output file '%s': %s" % (filename, str(e)), file=sys.stderr)
                         exit(ERR_OUTPUT)
                 print(result, file=out, end=newline_separator)
+            
+            if nb_result == 0: # elastalert return "results=[]" so get a error with out not def
+                if not fileprefix == None and not inc_filenane == None: #yml action
+                    try:
+                        filename = fileprefix + str(sigmafile.name)
+                        filename = filename.replace('.yml','_' + str(inc_filenane) + filename_ext)
+                        inc_filenane += 1
+                        out = open(filename, "w", encoding='utf-8')
+                    except (IOError, OSError) as e:
+                        print("Failed to open output file '%s': %s" % (filename, str(e)), file=sys.stderr)
+                        exit(ERR_OUTPUT)
+                elif  not fileprefix == None and inc_filenane == None: # a simple yml
+                    try:
+                        filename = fileprefix + str(sigmafile.name)
+                        filename = filename.replace('.yml',filename_ext) 
+                        out = open(filename, "w", encoding='utf-8')
+                    except (IOError, OSError) as e:
+                        print("Failed to open output file '%s': %s" % (filename, str(e)), file=sys.stderr)
+                        exit(ERR_OUTPUT) 
         
         except OSError as e:
             print("Failed to open Sigma file %s: %s" % (sigmafile, str(e)), file=sys.stderr)


Test patch: