From 49d464f97959c14051e1e7364a360da01eec460e Mon Sep 17 00:00:00 2001 From: Thomas Patzke Date: Tue, 20 Nov 2018 23:23:54 +0100 Subject: [PATCH 1/5] Fixed wildcards in es-qs backend --- tools/sigma/backends/elasticsearch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/sigma/backends/elasticsearch.py b/tools/sigma/backends/elasticsearch.py index c15d5a3ce..1ac6f4bb8 100644 --- a/tools/sigma/backends/elasticsearch.py +++ b/tools/sigma/backends/elasticsearch.py @@ -26,7 +26,7 @@ class ElasticsearchQuerystringBackend(SingleTextQueryBackend): identifier = "es-qs" active = True - reEscape = re.compile("([+\\-=!(){}\\[\\]^\"~:/]|\\\\(?![*?])|\\\\u|&&|\\|\\|)") + reEscape = re.compile("([\\s+\\-=!(){}\\[\\]^\"~:/]|\\\\(?![*?])|\\\\u|&&|\\|\\|)") reClear = re.compile("[<>]") andToken = " AND " orToken = " OR " @@ -34,7 +34,7 @@ class ElasticsearchQuerystringBackend(SingleTextQueryBackend): subExpression = "(%s)" listExpression = "(%s)" listSeparator = " " - valueExpression = "\"%s\"" + valueExpression = "%s" nullExpression = "NOT _exists_:%s" notNullExpression = "_exists_:%s" mapExpression = "%s:%s" From 9e28669c339e13bd7771e81002c04577021b92b9 Mon Sep 17 00:00:00 2001 From: Thomas Patzke Date: Wed, 21 Nov 2018 22:29:12 +0100 Subject: [PATCH 2/5] Backend es-qs return quotes on empty or whitespace-only string --- tools/sigma/backends/elasticsearch.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/sigma/backends/elasticsearch.py b/tools/sigma/backends/elasticsearch.py index 1ac6f4bb8..dbb51d105 100644 --- a/tools/sigma/backends/elasticsearch.py +++ b/tools/sigma/backends/elasticsearch.py @@ -40,6 +40,13 @@ class ElasticsearchQuerystringBackend(SingleTextQueryBackend): mapExpression = "%s:%s" mapListsSpecialHandling = False + def generateValueNode(self, node): + result = super().generateValueNode(node) + if result == "" or result.isspace(): + return '""' + else: + return result + class ElasticsearchDSLBackend(RulenameCommentMixin, BaseBackend): """ElasticSearch DSL backend""" identifier = 'es-dsl' From a1940c6eaae56de7edd4ade1778e444ac786ae47 Mon Sep 17 00:00:00 2001 From: Thomas Patzke Date: Wed, 21 Nov 2018 22:34:04 +0100 Subject: [PATCH 3/5] Simplified rule --- rules/proxy/proxy_empty_ua.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rules/proxy/proxy_empty_ua.yml b/rules/proxy/proxy_empty_ua.yml index faac0f93b..da28473a1 100644 --- a/rules/proxy/proxy_empty_ua.yml +++ b/rules/proxy/proxy_empty_ua.yml @@ -8,9 +8,8 @@ logsource: category: proxy detection: selection: - UserAgent: - # Empty string - as used by Powershell's (New-Object Net.WebClient).DownloadString - - '' + # Empty string - as used by Powershell's (New-Object Net.WebClient).DownloadString + UserAgent: '' condition: selection fields: - ClientIP From 26d888aec3a473d56ee5ea35c6ca8b26ac3bd07b Mon Sep 17 00:00:00 2001 From: Thomas Patzke Date: Wed, 21 Nov 2018 22:56:48 +0100 Subject: [PATCH 4/5] Removed "not null" handling code Feature was removed some time ago. --- tools/sigma/parser/rule.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tools/sigma/parser/rule.py b/tools/sigma/parser/rule.py index 6560aaa33..565562405 100644 --- a/tools/sigma/parser/rule.py +++ b/tools/sigma/parser/rule.py @@ -87,12 +87,6 @@ class SigmaParser: fields = [ fields ] for field in fields: cond.add(ConditionNULLValue(val=field)) - elif value == "not null": - fields = mapping.resolve_fieldname(key) - if type(fields) == str: - fields = [ fields ] - for field in fields: - cond.add(ConditionNotNULLValue(val=field)) else: cond.add(mapping.resolve(key, value, self)) From aa1a953a6556f0504fde9f04b23335cd4a8ca916 Mon Sep 17 00:00:00 2001 From: Thomas Patzke Date: Wed, 21 Nov 2018 23:22:38 +0100 Subject: [PATCH 5/5] Moved node dumping code to generic location --- tools/sigma/parser/condition.py | 35 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/tools/sigma/parser/condition.py b/tools/sigma/parser/condition.py index 16e4d5675..ef697e90b 100644 --- a/tools/sigma/parser/condition.py +++ b/tools/sigma/parser/condition.py @@ -24,6 +24,24 @@ COND_OR = 2 COND_NOT = 3 COND_NULL = 4 +# Debugging code +def dumpNode(node, indent=''): # pragma: no cover + """ + Recursively print the AST rooted at *node* for debugging. + """ + if hasattr(node, 'items'): + print("%s%s<%s>" % (indent, type(node).__name__, + type(node.items).__name__)) + if type(node.items) != list: + dumpNode(node.items, indent + ' ') + else: + for item in node.items: + dumpNode(item, indent + ' ') + else: + print("%s%s=%s" % (indent, type(node).__name__, + repr(node))) + return node + # Condition Tokenizer class SigmaConditionToken: """Token of a Sigma condition expression""" @@ -271,23 +289,6 @@ class SigmaConditionOptimizer: """ Optimizer for the parsed AST. """ - def _dumpNode(self, node, indent=''): # pragma: no cover - """ - Recursively print the AST rooted at *node* for debugging. - """ - if hasattr(node, 'items'): - print("%s%s<%s>" % (indent, type(node).__name__, - type(node.items).__name__)) - if type(node.items) != list: - self._dumpNode(node.items, indent + ' ') - else: - for item in node.items: - self._dumpNode(item, indent + ' ') - else: - print("%s%s=%s" % (indent, type(node).__name__, - repr(node))) - return node - def _stripSubexpressionNode(self, node): """ Recursively strips all subexpressions (i.e. brackets) from the AST.