# Output backends for sigmac # Copyright 2016-2018 Thomas Patzke, Florian Roth, Roey # 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 sigma from .base import SingleTextQueryBackend from .mixins import MultiRuleOutputMixin class SplunkBackend(SingleTextQueryBackend): """Converts Sigma rule into Splunk Search Processing Language (SPL).""" identifier = "splunk" active = True index_field = "index" reEscape = re.compile('("|\\\\(?![*?]))') reClear = None andToken = " " orToken = " OR " notToken = "NOT " subExpression = "(%s)" listExpression = "(%s)" listSeparator = " " valueExpression = "\"%s\"" nullExpression = "NOT %s=\"*\"" notNullExpression = "%s=\"*\"" mapExpression = "%s=%s" mapListsSpecialHandling = True mapListValueExpression = "%s IN %s" def generateMapItemListNode(self, key, value): return "(" + (" OR ".join(['%s=%s' % (key, self.generateValueNode(item)) for item in value])) + ")" def generateAggregation(self, agg): if agg == None: return "" if agg.aggfunc == sigma.parser.condition.SigmaAggregationParser.AGGFUNC_NEAR: raise NotImplementedError("The 'near' aggregation operator is not yet implemented for this backend") if agg.groupfield == None: return " | stats %s(%s) as val | search val %s %s" % (agg.aggfunc_notrans, agg.aggfield or "", agg.cond_op, agg.condition) else: return " | stats %s(%s) as val by %s | search val %s %s" % (agg.aggfunc_notrans, agg.aggfield or "", agg.groupfield or "", agg.cond_op, agg.condition) class SplunkXMLBackend(SingleTextQueryBackend, MultiRuleOutputMixin): """Converts Sigma rule into XML used for Splunk Dashboard Panels""" identifier = "splunkxml" active = True index_field = "index" panel_pre = "" panel_inf = "" panel_suf = "$field1.earliest$$field1.latest$1" \ "" \ "
" dash_pre = "
" \ "-24h@hnow
" dash_suf = "
" queries = dash_pre reEscape = re.compile('("|\\\\(?![*?]))') reClear = SplunkBackend.reClear andToken = SplunkBackend.andToken orToken = SplunkBackend.orToken notToken = SplunkBackend.notToken subExpression = SplunkBackend.subExpression listExpression = SplunkBackend.listExpression listSeparator = SplunkBackend.listSeparator valueExpression = SplunkBackend.valueExpression nullExpression = SplunkBackend.nullExpression notNullExpression = SplunkBackend.notNullExpression mapExpression = SplunkBackend.mapExpression mapListsSpecialHandling = SplunkBackend.mapListsSpecialHandling mapListValueExpression = SplunkBackend.mapListValueExpression def generateMapItemListNode(self, key, value): return "(" + (" OR ".join(['%s=%s' % (key, self.generateValueNode(item)) for item in value])) + ")" def generateAggregation(self, agg): if agg == None: return "" if agg.aggfunc == sigma.parser.condition.SigmaAggregationParser.AGGFUNC_NEAR: return "" if agg.groupfield == None: return " | stats %s(%s) as val | search val %s %s" % (agg.aggfunc_notrans, agg.aggfield or "", agg.cond_op, agg.condition) else: return " | stats %s(%s) as val by %s | search val %s %s" % (agg.aggfunc_notrans, agg.aggfield or "", agg.groupfield or "", agg.cond_op, agg.condition) def generate(self, sigmaparser): """Method is called for each sigma rule and receives the parsed rule (SigmaParser)""" for parsed in sigmaparser.condparsed: query = self.generateQuery(parsed) if query is not None: self.queries += self.panel_pre self.queries += self.getRuleName(sigmaparser) self.queries += self.panel_inf query = query.replace("<", "<") query = query.replace(">", ">") self.queries += query self.queries += self.panel_suf def finalize(self): self.queries += self.dash_suf return self.queries