mirror of
https://github.com/valitydev/SigmaHQ.git
synced 2024-11-08 18:23:52 +00:00
92 lines
3.8 KiB
Python
92 lines
3.8 KiB
Python
|
import sigma
|
||
|
from sigma.parser.modifiers.base import SigmaTypeModifier
|
||
|
from sigma.parser.modifiers.type import SigmaRegularExpressionModifier
|
||
|
from .base import SingleTextQueryBackend
|
||
|
|
||
|
|
||
|
class STIXBackend(SingleTextQueryBackend):
|
||
|
"""Converts Sigma rule into STIX pattern."""
|
||
|
identifier = "stix"
|
||
|
active = True
|
||
|
andToken = " AND "
|
||
|
orToken = " OR "
|
||
|
notToken = "NOT "
|
||
|
subExpression = "(%s)"
|
||
|
valueExpression = "\'%s\'"
|
||
|
mapExpression = "%s = %s"
|
||
|
mapListsSpecialHandling = True
|
||
|
|
||
|
def cleanKey(self, key):
|
||
|
if key is None:
|
||
|
raise TypeError("Backend does not support empty key " + str(key))
|
||
|
else:
|
||
|
return key
|
||
|
|
||
|
def cleanValue(self, value):
|
||
|
return value
|
||
|
|
||
|
def generateMapItemListNode(self, key, value):
|
||
|
items_list = list()
|
||
|
for item in value:
|
||
|
if type(item) == str and "*" in item:
|
||
|
item = item.replace("*", "%")
|
||
|
items_list.append('%s LIKE %s' % (self.cleanKey(key), self.generateValueNode(item)))
|
||
|
else:
|
||
|
items_list.append('%s = %s' % (self.cleanKey(key), self.generateValueNode(item)))
|
||
|
return '('+" OR ".join(items_list)+')'
|
||
|
|
||
|
def generateMapItemTypedNode(self, key, value):
|
||
|
if type(value) == SigmaRegularExpressionModifier:
|
||
|
regex = str(value)
|
||
|
# Regular Expressions have to match the full value in QRadar
|
||
|
if not (regex.startswith('^') or regex.startswith('.*')):
|
||
|
regex = '.*' + regex
|
||
|
if not (regex.endswith('$') or regex.endswith('.*')):
|
||
|
regex = regex + '.*'
|
||
|
return "%s MATCHES %s" % (self.cleanKey(key), self.generateValueNode(regex))
|
||
|
else:
|
||
|
raise NotImplementedError("Type modifier '{}' is not supported by backend".format(value.identifier))
|
||
|
|
||
|
def generateMapItemNode(self, node):
|
||
|
key, value = node
|
||
|
if ":" not in key:
|
||
|
raise TypeError("Backend does not support mapping for key " + str(key))
|
||
|
if self.mapListsSpecialHandling == False and type(value) in (str, int, list) or self.mapListsSpecialHandling == True and type(value) in (str, int):
|
||
|
if type(value) == str and "*" in value:
|
||
|
value = value.replace("*", "%")
|
||
|
return "%s LIKE %s" % (self.cleanKey(key), self.generateValueNode(value))
|
||
|
elif type(value) in (str, int):
|
||
|
return self.mapExpression % (self.cleanKey(key), self.generateValueNode(value))
|
||
|
elif type(value) == list:
|
||
|
return self.generateMapItemListNode(key, value)
|
||
|
elif isinstance(value, SigmaTypeModifier):
|
||
|
return self.generateMapItemTypedNode(key, value)
|
||
|
else:
|
||
|
raise TypeError("Backend does not support map values of type " + str(type(value)))
|
||
|
|
||
|
def generateValueNode(self, node):
|
||
|
return self.valueExpression % (self.cleanValue(str(node)))
|
||
|
|
||
|
def generateNode(self, node):
|
||
|
if type(node) == sigma.parser.condition.ConditionAND:
|
||
|
return self.generateANDNode(node)
|
||
|
elif type(node) == sigma.parser.condition.ConditionOR:
|
||
|
return self.generateORNode(node)
|
||
|
elif type(node) == sigma.parser.condition.ConditionNOT:
|
||
|
return self.generateNOTNode(node)
|
||
|
elif type(node) == sigma.parser.condition.NodeSubexpression:
|
||
|
return self.generateSubexpressionNode(node)
|
||
|
elif type(node) == tuple:
|
||
|
return self.generateMapItemNode(node)
|
||
|
else:
|
||
|
raise TypeError("Node type %s was not expected in Sigma parse tree" % (str(type(node))))
|
||
|
|
||
|
def generate(self, sigmaparser):
|
||
|
for parsed in sigmaparser.condparsed:
|
||
|
query = self.generateQuery(parsed, sigmaparser)
|
||
|
return "[" + query + "]"
|
||
|
|
||
|
def generateQuery(self, parsed, sigmaparser):
|
||
|
result = self.generateNode(parsed.parsedSearch)
|
||
|
return result
|