2020-02-22 20:50:30 -08:00
|
|
|
import re
|
2020-02-22 20:59:56 -08:00
|
|
|
from .base import SingleTextQueryBackend
|
2020-02-22 20:50:30 -08:00
|
|
|
import json
|
|
|
|
|
|
2020-02-22 20:59:56 -08:00
|
|
|
class LogiqBackend(SingleTextQueryBackend):
|
|
|
|
|
"""Converts Sigma rule into LOGIQ event rule api payload """
|
2020-02-22 20:50:30 -08:00
|
|
|
identifier = "logiq"
|
|
|
|
|
config_required = False
|
2020-02-22 20:59:56 -08:00
|
|
|
active = True
|
|
|
|
|
reEscape = re.compile('(")')
|
|
|
|
|
reClear = None
|
|
|
|
|
andToken = " && "
|
|
|
|
|
orToken = " || "
|
|
|
|
|
notToken = " !~ "
|
|
|
|
|
subExpression = "%s"
|
|
|
|
|
listExpression = "%s"
|
|
|
|
|
listSeparator = ", "
|
|
|
|
|
valueExpression = "message =~ \'%s\'"
|
|
|
|
|
keyExpression = "%s"
|
2020-04-08 23:43:46 +02:00
|
|
|
nullExpression = "!~ %s"
|
2020-02-22 20:59:56 -08:00
|
|
|
notNullExpression = "!%s"
|
|
|
|
|
mapExpression = "(%s=%s)"
|
|
|
|
|
mapListsSpecialHandling = True
|
2020-02-22 20:50:30 -08:00
|
|
|
|
|
|
|
|
reEscape = re.compile("([\\|()\[\]{}.^$+])")
|
|
|
|
|
|
|
|
|
|
def generate(self, sigmaparser):
|
|
|
|
|
"""Method is called for each sigma rule and receives the parsed rule (SigmaParser)"""
|
|
|
|
|
|
|
|
|
|
eventRule = dict()
|
|
|
|
|
eventRule["name"] = sigmaparser.parsedyaml["title"]
|
2020-04-08 23:43:46 +02:00
|
|
|
eventRule["groupName"] = sigmaparser.parsedyaml["logsource"].get("product", "")
|
2020-02-22 20:50:30 -08:00
|
|
|
eventRule["description"] = sigmaparser.parsedyaml["description"]
|
|
|
|
|
eventRule["condition"] = sigmaparser.parsedyaml["detection"]
|
|
|
|
|
eventRule["level"] = sigmaparser.parsedyaml["level"]
|
|
|
|
|
|
|
|
|
|
for parsed in sigmaparser.condparsed:
|
|
|
|
|
query = self.generateQuery(parsed)
|
|
|
|
|
before = self.generateBefore(parsed)
|
|
|
|
|
after = self.generateAfter(parsed)
|
|
|
|
|
|
|
|
|
|
eventRule["condition"] = ""
|
|
|
|
|
if before is not None:
|
|
|
|
|
eventRule["condition"] = before
|
|
|
|
|
if query is not None:
|
|
|
|
|
eventRule["condition"] += query
|
|
|
|
|
if after is not None:
|
|
|
|
|
eventRule["condition"] += after
|
|
|
|
|
|
2020-02-22 20:59:56 -08:00
|
|
|
return json.dumps(eventRule)
|
2020-02-22 20:50:30 -08:00
|
|
|
|
|
|
|
|
def cleanValue(self, val):
|
2020-04-08 23:43:46 +02:00
|
|
|
if val.startswith('*'):
|
2020-02-22 20:50:30 -08:00
|
|
|
val = val.replace("*","/*")
|
2020-02-22 20:59:56 -08:00
|
|
|
|
2020-02-22 20:50:30 -08:00
|
|
|
return val
|
|
|
|
|
|
|
|
|
|
def generateListNode(self, node):
|
|
|
|
|
if not set([type(value) for value in node]).issubset({str, int}):
|
|
|
|
|
raise TypeError("List values must be strings or numbers")
|
|
|
|
|
return self.generateORNode(node)
|