Repository: SigmaHQ/sigma

Issue:
`es-eql` special character escaping in query
It appears that special character escaping is broken for the `es-eql` backend currently. For example, the rule `windows/process_creation/process_creation_syncappvpublishingserver_vbs_execute_powershell.yml` produces this output:

```
process where event.type : "start" and (process.args : "*"n;*" and process.args : "*\\SyncAppvPublishingServer.vbs*")
```

Whereas it should produce the following properly escaped query:

```
process where event.type : "start" and (process.args : "*\"n;*" and process.args : "*\\SyncAppvPublishingServer.vbs*")
```

I'm relatively new to this repo, but I did some digging/testing for a solution. It appears that the `ElasticsearchEQLBackend` class doesn't configure the `QuoteCharMixin`, but does use the `cleanValue` method, and adds an extra `escapeSlashes` method. Based on some local testing, it seems that doing the following in `ElasticsearchEQLBackend` fixes the problem for me:

```patch
diff --git a/tools/sigma/backends/elasticsearch.py b/tools/sigma/backends/elasticsearch.py
index a69ba73..949db2b 100644
--- a/tools/sigma/backends/elasticsearch.py
+++ b/tools/sigma/backends/elasticsearch.py
@@ -422,6 +422,7 @@ class ElasticsearchEQLBackend(DeepFieldMappingMixin, ElasticsearchWildcardHandli
     mapExpression = "%s : %s"
     mapListsSpecialHandling = False
     mapListValueExpression = "%s : %s"
+    reEscape = re.compile('(["\\\\])')

     sort_condition_lists = True

@@ -438,9 +439,6 @@ class ElasticsearchEQLBackend(DeepFieldMappingMixin, ElasticsearchWildcardHandli
         self.maxspan = None
         return super().generate(sigmaparser)

-    def escapeSlashes(self, value):
-        return value.replace("\\", "\\\\")
-
     def generateMapItemNode(self, node):
         fieldname, _ = node
         try:
@@ -456,7 +454,7 @@ class ElasticsearchEQLBackend(DeepFieldMappingMixin, ElasticsearchWildcardHandli
         return self.mapExpression % (fieldname, self.generateTypedValueNode(value))

     def generateValueNode(self, node):
-        return self.valueExpression % (self.escapeSlashes(self.cleanValue(str(node))))
+        return self.valueExpression % (self.cleanValue(str(node)))

     def generateAggregationQuery(self, agg, searchId):
         condtoken = SigmaConditionTokenizer(searchId)
```

This would remove the need for the `escapeSlashes` method completely, and actually utilizes `QuoteCharMixin`.

If there's something I missed, please let me know, but if this solution sounds acceptable, I'm happy to open a PR. :+1: I know that you are moving to `pySigma`, but there doesn't appear to be support for Elastic/EQL there yet.


Discussion:
I would be happy about the PR... It fixes the issue and reduces the complexity, exactly what we want 😊

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
@@ -422,6 +422,7 @@ class ElasticsearchEQLBackend(DeepFieldMappingMixin, ElasticsearchWildcardHandli
     mapExpression = "%s : %s"
     mapListsSpecialHandling = False
     mapListValueExpression = "%s : %s"
+    reEscape = re.compile('(["\\\\])')
 
     sort_condition_lists = True
 
@@ -438,9 +439,6 @@ def generate(self, sigmaparser):
         self.maxspan = None
         return super().generate(sigmaparser)
 
-    def escapeSlashes(self, value):
-        return value.replace("\\", "\\\\")
-
     def generateMapItemNode(self, node):
         fieldname, _ = node
         try:
@@ -456,7 +454,7 @@ def generateMapItemTypedNode(self, fieldname, value):
         return self.mapExpression % (fieldname, self.generateTypedValueNode(value))
 
     def generateValueNode(self, node):
-        return self.valueExpression % (self.escapeSlashes(self.cleanValue(str(node))))
+        return self.valueExpression % (self.cleanValue(str(node)))
 
     def generateAggregationQuery(self, agg, searchId):
         condtoken = SigmaConditionTokenizer(searchId)


Test patch: