From d42409372c1fa5eed5b802a1a80306776158726f Mon Sep 17 00:00:00 2001 From: vh Date: Mon, 30 Dec 2019 16:09:19 +0200 Subject: [PATCH 1/5] Azure Sentinel backend (ala) - Fixed path in query Added new backend Azure Sentinel Rule (ala-rule) --- tools/sigma/backends/ala-rule.py | 79 ++++++++++++++++++++++++++++++++ tools/sigma/backends/ala.py | 4 ++ 2 files changed, 83 insertions(+) create mode 100644 tools/sigma/backends/ala-rule.py diff --git a/tools/sigma/backends/ala-rule.py b/tools/sigma/backends/ala-rule.py new file mode 100644 index 000000000..09c9ebec8 --- /dev/null +++ b/tools/sigma/backends/ala-rule.py @@ -0,0 +1,79 @@ +# Azure Log Analytics output backend for sigmac +# John Tuckner (@tuckner) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +import re +import xml.etree.ElementTree as xml + +from sigma.backends.ala import AzureLogAnalyticsBackend +from .base import SingleTextQueryBackend +from .data import sysmon_schema +from .exceptions import NotSupportedError + +class AzureAPIBackend(AzureLogAnalyticsBackend): + """Converts Sigma rule into Azure Log Analytics Queries.""" + identifier = "ala-rule" + active = True + options = SingleTextQueryBackend.options + ( + ("sysmon", False, "Generate Sysmon event queries for generic rules", None), + ) + + + def __init__(self, *args, **kwargs): + """Initialize field mappings""" + super().__init__(*args, **kwargs) + + + def create_rule(self, config): + tags = config.get("tags") + tactics = list() + technics = list() + for tag in tags: + tag = tag.replace("attack.", "") + if re.match("[tT][0-9]{4}", tag): + technics.append(tag.title()) + else: + if "_" in tag: + tag_list = tag.split("_") + tag_list = [item.title() for item in tag_list] + tactics.append("".join(tag_list)) + + rule = { + "analytics": + [ + { + "displayName": "{} by {}".format(config.get("title"), config.get('author')), + "description": "{} {}".format(config.get("description"), "Technics: {}.".format(",".join(technics))), + "severity": config.get("level"), + "enabled": True, + "query": config.get("translation"), + "queryFrequency": "12H", + "queryPeriod": "12H", + "triggerOperator": "GreaterThan", + "triggerThreshold": 1, + "suppressionDuration": "12H", + "suppressionEnabled": False, + "tactics": tactics + } + ] + } + return rule + + def generate(self, sigmaparser): + translation = super().generate(sigmaparser) + configs = sigmaparser.parsedyaml + configs.update({"translation": translation}) + rule = self.create_rule(configs) + return rule diff --git a/tools/sigma/backends/ala.py b/tools/sigma/backends/ala.py index 422ba5a34..1f051000b 100644 --- a/tools/sigma/backends/ala.py +++ b/tools/sigma/backends/ala.py @@ -87,6 +87,10 @@ class AzureLogAnalyticsBackend(SingleTextQueryBackend): op = "endswith" val = self.cleanValue(val[1:]) + if "\\" in val: + #val = val.replace("\\", "\\\\") + return "%s @\"%s\"" % (op, val) + return "%s \"%s\"" % (op, val) def generate(self, sigmaparser): From f015c97dffebb23a69016f7d484c8c6e04f10a8d Mon Sep 17 00:00:00 2001 From: SOC Prime <37212749+socprime@users.noreply.github.com> Date: Mon, 30 Dec 2019 16:13:27 +0200 Subject: [PATCH 2/5] Update ala-rule.py --- tools/sigma/backends/ala-rule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/sigma/backends/ala-rule.py b/tools/sigma/backends/ala-rule.py index 09c9ebec8..e368cc689 100644 --- a/tools/sigma/backends/ala-rule.py +++ b/tools/sigma/backends/ala-rule.py @@ -23,7 +23,7 @@ from .data import sysmon_schema from .exceptions import NotSupportedError class AzureAPIBackend(AzureLogAnalyticsBackend): - """Converts Sigma rule into Azure Log Analytics Queries.""" + """Converts Sigma rule into Azure Log Analytics Rule.""" identifier = "ala-rule" active = True options = SingleTextQueryBackend.options + ( From 92bc96a308d0caae004a08046a43276250bf1f27 Mon Sep 17 00:00:00 2001 From: SOC Prime <37212749+socprime@users.noreply.github.com> Date: Mon, 30 Dec 2019 16:26:30 +0200 Subject: [PATCH 3/5] Update ala-rule.py --- tools/sigma/backends/ala-rule.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/sigma/backends/ala-rule.py b/tools/sigma/backends/ala-rule.py index e368cc689..ebf535b0a 100644 --- a/tools/sigma/backends/ala-rule.py +++ b/tools/sigma/backends/ala-rule.py @@ -1,5 +1,4 @@ -# Azure Log Analytics output backend for sigmac -# John Tuckner (@tuckner) +# Azure Log Analytics Rule output backend for sigmac # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by @@ -49,13 +48,15 @@ class AzureAPIBackend(AzureLogAnalyticsBackend): tag_list = tag.split("_") tag_list = [item.title() for item in tag_list] tactics.append("".join(tag_list)) + else: + tactics.append(tag.title()) rule = { "analytics": [ { "displayName": "{} by {}".format(config.get("title"), config.get('author')), - "description": "{} {}".format(config.get("description"), "Technics: {}.".format(",".join(technics))), + "description": "{} {}".format(config.get("description"), "Technique: {}.".format(",".join(technics))), "severity": config.get("level"), "enabled": True, "query": config.get("translation"), From 7b62b931cefeff9af8862b93154d3b52971b6591 Mon Sep 17 00:00:00 2001 From: Thomas Patzke Date: Mon, 13 Jan 2020 11:23:59 +0100 Subject: [PATCH 4/5] Moved ala-rule backend code into ala backend module --- tools/sigma/backends/ala-rule.py | 80 -------------------------------- tools/sigma/backends/ala.py | 56 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 80 deletions(-) delete mode 100644 tools/sigma/backends/ala-rule.py diff --git a/tools/sigma/backends/ala-rule.py b/tools/sigma/backends/ala-rule.py deleted file mode 100644 index ebf535b0a..000000000 --- a/tools/sigma/backends/ala-rule.py +++ /dev/null @@ -1,80 +0,0 @@ -# Azure Log Analytics Rule output backend for sigmac - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. - -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see . - -import re -import xml.etree.ElementTree as xml - -from sigma.backends.ala import AzureLogAnalyticsBackend -from .base import SingleTextQueryBackend -from .data import sysmon_schema -from .exceptions import NotSupportedError - -class AzureAPIBackend(AzureLogAnalyticsBackend): - """Converts Sigma rule into Azure Log Analytics Rule.""" - identifier = "ala-rule" - active = True - options = SingleTextQueryBackend.options + ( - ("sysmon", False, "Generate Sysmon event queries for generic rules", None), - ) - - - def __init__(self, *args, **kwargs): - """Initialize field mappings""" - super().__init__(*args, **kwargs) - - - def create_rule(self, config): - tags = config.get("tags") - tactics = list() - technics = list() - for tag in tags: - tag = tag.replace("attack.", "") - if re.match("[tT][0-9]{4}", tag): - technics.append(tag.title()) - else: - if "_" in tag: - tag_list = tag.split("_") - tag_list = [item.title() for item in tag_list] - tactics.append("".join(tag_list)) - else: - tactics.append(tag.title()) - - rule = { - "analytics": - [ - { - "displayName": "{} by {}".format(config.get("title"), config.get('author')), - "description": "{} {}".format(config.get("description"), "Technique: {}.".format(",".join(technics))), - "severity": config.get("level"), - "enabled": True, - "query": config.get("translation"), - "queryFrequency": "12H", - "queryPeriod": "12H", - "triggerOperator": "GreaterThan", - "triggerThreshold": 1, - "suppressionDuration": "12H", - "suppressionEnabled": False, - "tactics": tactics - } - ] - } - return rule - - def generate(self, sigmaparser): - translation = super().generate(sigmaparser) - configs = sigmaparser.parsedyaml - configs.update({"translation": translation}) - rule = self.create_rule(configs) - return rule diff --git a/tools/sigma/backends/ala.py b/tools/sigma/backends/ala.py index 1f051000b..81124d983 100644 --- a/tools/sigma/backends/ala.py +++ b/tools/sigma/backends/ala.py @@ -172,3 +172,59 @@ class AzureLogAnalyticsBackend(SingleTextQueryBackend): raise TypeError("Backend does not support map values of type " + str(type(value))) return super().generateMapItemNode(node) + +class AzureAPIBackend(AzureLogAnalyticsBackend): + """Converts Sigma rule into Azure Log Analytics Rule.""" + identifier = "ala-rule" + active = True + options = SingleTextQueryBackend.options + ( + ("sysmon", False, "Generate Sysmon event queries for generic rules", None), + ) + + def __init__(self, *args, **kwargs): + """Initialize field mappings""" + super().__init__(*args, **kwargs) + + def create_rule(self, config): + tags = config.get("tags") + tactics = list() + technics = list() + for tag in tags: + tag = tag.replace("attack.", "") + if re.match("[tT][0-9]{4}", tag): + technics.append(tag.title()) + else: + if "_" in tag: + tag_list = tag.split("_") + tag_list = [item.title() for item in tag_list] + tactics.append("".join(tag_list)) + else: + tactics.append(tag.title()) + + rule = { + "analytics": + [ + { + "displayName": "{} by {}".format(config.get("title"), config.get('author')), + "description": "{} {}".format(config.get("description"), "Technique: {}.".format(",".join(technics))), + "severity": config.get("level"), + "enabled": True, + "query": config.get("translation"), + "queryFrequency": "12H", + "queryPeriod": "12H", + "triggerOperator": "GreaterThan", + "triggerThreshold": 1, + "suppressionDuration": "12H", + "suppressionEnabled": False, + "tactics": tactics + } + ] + } + return rule + + def generate(self, sigmaparser): + translation = super().generate(sigmaparser) + configs = sigmaparser.parsedyaml + configs.update({"translation": translation}) + rule = self.create_rule(configs) + return rule From 638d461b164ee2d1e566e79f9e230d9d0a07a556 Mon Sep 17 00:00:00 2001 From: Thomas Patzke Date: Mon, 13 Jan 2020 13:47:11 +0100 Subject: [PATCH 5/5] Added ala-rule backend to CI testing --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index bffeee09b..2b5cb4436 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,7 @@ test-sigmac: coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t logpoint -c tools/config/logpoint-windows.yml rules/ > /dev/null coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t wdatp rules/ > /dev/null coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t ala rules/ > /dev/null + coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t ala-rule rules/ > /dev/null coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t ala --backend-config tests/backend_config.yml rules/windows/process_creation/ > /dev/null coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t es-dsl -c tools/config/winlogbeat.yml rules/ > /dev/null coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t powershell -c tools/config/powershell.yml -Ocsv rules/ > /dev/null