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 diff --git a/tools/sigma/backends/elasticsearch.py b/tools/sigma/backends/elasticsearch.py index c15d5a3ce..dbb51d105 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,12 +34,19 @@ class ElasticsearchQuerystringBackend(SingleTextQueryBackend): subExpression = "(%s)" listExpression = "(%s)" listSeparator = " " - valueExpression = "\"%s\"" + valueExpression = "%s" nullExpression = "NOT _exists_:%s" notNullExpression = "_exists_:%s" 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' 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. 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))