Skip to content

Commit

Permalink
Improved testing and removed dead&debug code
Browse files Browse the repository at this point in the history
  • Loading branch information
thomaspatzke committed Jun 28, 2019
1 parent 377872c commit 6fab5d7
Show file tree
Hide file tree
Showing 2 changed files with 1 addition and 75 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ test-sigmac:
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t qradar -c tools/config/qradar.yml rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t qualys -c tools/config/qualys.yml rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t netwitness -c tools/config/netwitness.yml rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t sumologic -c tools/config/sumologic.yml rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t sumologic -O rulecomment -c tools/config/sumologic.yml rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t splunk -c tools/config/splunk-windows-all-index.yml -f 'level>=high,level<=critical,status=stable,logsource=windows,tag=attack.execution' rules/ > /dev/null
! coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t splunk -c tools/config/splunk-windows-all-index.yml -f 'level>=high,level<=critical,status=xstable,logsource=windows' rules/ > /dev/null
! coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t splunk -c tools/config/splunk-windows-all-index.yml -f 'level>=high,level<=xcritical,status=stable,logsource=windows' rules/ > /dev/null
Expand Down
74 changes: 0 additions & 74 deletions tools/sigma/backends/sumologic.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,8 @@ class SumoLogicBackend(SingleTextQueryBackend):
"""Converts Sigma rule into SumoLogic query"""
identifier = "sumologic"
active = True
# debug = True
debug = False

index_field = "_index"
# reEscape = re.compile('("|\\\\(?![*?]))')
reClear = None
andToken = " AND "
orToken = " OR "
Expand All @@ -54,8 +51,6 @@ class SumoLogicBackend(SingleTextQueryBackend):
logname = None

def generateAggregation(self, agg):
if not agg:
return ""
# lnx_shell_priv_esc_prep.yml
# print("DEBUG generateAggregation(): %s, %s, %s, %s" % (agg.aggfunc_notrans, agg.aggfield, agg.groupfield, agg.cond_op))
if agg.groupfield == 'host':
Expand All @@ -81,8 +76,6 @@ def generateAggregation(self, agg):

def generateBefore(self, parsed):
# not required but makes query faster, especially if no FER or _index/_sourceCategory
if self.debug:
print("DEBUG generateBefore(): %s, %s, %s, %s" % (self.logname, self.indices, self.product, self.service))
if self.logname:
return "%s " % self.logname
# FIXME! don't get backend config mapping through generate() => mapping inside script
Expand Down Expand Up @@ -118,11 +111,7 @@ def generate(self, sigmaparser):
except KeyError:
self.category = None
# FIXME! don't get backend config mapping
if self.debug:
print("DEBUG sigmaconfig: %s" % self.sigmaconfig)
self.indices = sigmaparser.get_logsource().index
if self.debug:
print("DEBUG indices: %s" % self.indices)
if len(self.indices) == 0:
self.indices = None
try:
Expand All @@ -131,21 +120,13 @@ def generate(self, sigmaparser):
pass

for parsed in sigmaparser.condparsed:
if self.debug:
print("DEBUG generate0: %s" % parsed)
query = self.generateQuery(parsed)
# FIXME! exclude if expression is regexp but anyway, not directly supported.
# Not doing if aggregation ('| count') or key ('=')
if not (query.startswith('"') and query.endswith('"')) and not (query.startswith('(') and query.endswith(')')) and not ('|' in query) and not ('=' in query):
query = '"%s"' % query
if self.debug:
print("DEBUG generate1q: %s" % query)
before = self.generateBefore(parsed)
if self.debug:
print("DEBUG generate1b: %s" % before)
after = self.generateAfter(parsed)
if self.debug:
print("DEBUG generate1a: %s" % after)

result = ""
if before is not None:
Expand Down Expand Up @@ -181,10 +162,6 @@ def __init__(self, *args, **kwargs):
# Clearing values from special characters.
# Sumologic: only removing '*' (in quotes, is litteral. without, is wildcard) and '"'
def CleanNode(self, node):
if self.debug:
print("DEBUG CleanNode0: %s" % node)
# search_ptrn = re.compile(r"[\/@?#&%*\(\)\"]")
# search_ptrn = re.compile(r"[*\"\\]")
search_ptrn = re.compile(r"[*\"\\]")
replace_ptrn = re.compile(r"[*\"\\]")
match = search_ptrn.search(str(node))
Expand All @@ -196,28 +173,16 @@ def CleanNode(self, node):
else:
new_node.append(node)
node = new_node
if self.debug:
print("DEBUG CleanNode1: %s" % node)
return node

# Clearing values from special characters.
def generateMapItemNode(self, node):
if self.debug:
try:
print("DEBUG generateMapItemNode0: %s" % node)
except TypeError:
print("EXCEPT generateMapItemNode0")
key, value = node
if key in self.allowedFieldsList:
if not self.mapListsSpecialHandling and type(value) in (
str, int, list) or self.mapListsSpecialHandling and type(value) in (str, int):
if key in ("LogName", "source"):
self.logname = value
if self.debug:
try:
print("DEBUG generateMapItemNode1: %s" % node)
except TypeError:
print("EXCEPT generateMapItemNode1")
# need cleanValue if sigma entry with single quote
return self.mapExpression % (key, self.cleanValue(value, key))
elif type(value) is list:
Expand Down Expand Up @@ -265,47 +230,29 @@ def generateMapItemNode(self, node):
# => OK only if field entry with list, not string
# => generateNode: call cleanValue
def cleanValue(self, val, key=''):
if self.debug:
print("DEBUG cleanValue0: %s" % val)
if self.reEscape:
val = self.reEscape.sub(self.escapeSubst, val)
if self.reClear:
val = self.reClear.sub("", val)
# in sumologic, if key, can use wildcard outside of double quotes. if inside, it's litteral
if key:
val = re.sub(r'\"', '\\"', str(val))
val = re.sub(r'(.+)\*(.+)', '"\g<1>"*"\g<2>"', val, 0)
val = re.sub(r'^\*', '*"', val)
val = re.sub(r'\*$', '"*', val)
if self.debug:
print("DEBUG cleanValue0a: %s" % val)
# if unbalanced wildcard?
if val.startswith('*"') and not (val.endswith('"*') or val.endswith('"')):
val = val + '"'
if val.endswith('"*') and not (val.startswith('*"') or val.startswith('"')):
val = '"' + val
if self.debug:
print("DEBUG cleanValue0b: %s" % val)
# double escape if end quote
if val.endswith('\\"*') and not val.endswith('\\\\"*'):
val = re.sub(r'\\"\*$', '\\\\\\"*', val)
if self.debug:
print("DEBUG cleanValue0c: %s" % val)
# if not key and not (val.startswith('"') and val.endswith('"')) and not (val.startswith('(') and val.endswith(')')) and not ('|' in val) and val:
# apt_babyshark.yml
if not (val.startswith('"') and val.endswith('"')) and not (val.startswith('(') and val.endswith(')')) and not ('|' in val) and not ('*' in val) and val:
val = '"%s"' % val
if self.debug:
print("DEBUG cleanValue1: %s" % val)
return val

# for keywords values with space
def generateValueNode(self, node, key=''):
if self.debug:
print("DEBUG generateValueNode0: %s, %s" % (node, key))
cV = self.cleanValue(str(node), key)
if self.debug:
print("DEBUG generateValueNode1: %s, %s" % (node, key))
if type(node) is int:
return cV
if 'AND' in node and cV:
Expand All @@ -314,22 +261,16 @@ def generateValueNode(self, node, key=''):
return cV

def generateMapItemListNode(self, key, value):
if self.debug:
print("DEBUG generateMapItemListNode0: %s, %s" % (key, value))
itemslist = list()
for item in value:
if key in self.allowedFieldsList:
itemslist.append('%s = %s' % (key, self.generateValueNode(item, key)))
else:
itemslist.append('%s' % (self.generateValueNode(item)))
if self.debug:
print("DEBUG generateMapItemListNode1: %s, %s" % (key, value))
return "(" + " OR ".join(itemslist) + ")"

# generateORNode algorithm for ArcSightBackend & SumoLogicBackend class.
def generateORNode(self, node):
if self.debug:
print("DEBUG generateORNode0: %s" % node)
if type(node) == ConditionOR and all(isinstance(item, str) for item in node):
new_value = list()
for value in node:
Expand All @@ -338,20 +279,5 @@ def generateORNode(self, node):
new_value.append(self.andToken.join([self.valueExpression % val for val in value]))
else:
new_value.append(value)
if self.debug:
print("DEBUG generateORNode1: %s" % node)
return "(" + self.orToken.join([self.generateNode(val) for val in new_value]) + ")"
if self.debug:
print("DEBUG generateORNode1b: %s" % node)
return "(" + self.orToken.join([self.generateNode(val) for val in node]) + ")"

def fieldNameMapping(self, fieldname, value):
"""
Alter field names depending on the value(s). Backends may use this
method to perform a final transformation of the field name
in addition to the field mapping defined in the conversion
configuration. The field name passed to this method was already
transformed from the original name given in the Sigma rule.
TODO/FIXME!
"""
return fieldname

0 comments on commit 6fab5d7

Please sign in to comment.