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 diff --git a/tools/sigma/backends/ala.py b/tools/sigma/backends/ala.py index 422ba5a34..81124d983 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): @@ -168,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