diff --git a/Makefile b/Makefile
index a9a5a0f6f..8439b5dd7 100644
--- a/Makefile
+++ b/Makefile
@@ -57,6 +57,7 @@ test-sigmac:
$(COVERAGE) run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t carbonblack -c tools/config/carbon-black.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 netwitness-epl -c netwitness-epl 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 humio -O rulecomment -c tools/config/humio.yml rules/ > /dev/null
$(COVERAGE) run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t crowdstrike -O rulecomment -c tools/config/crowdstrike.yml rules/ > /dev/null
@@ -64,6 +65,7 @@ test-sigmac:
$(COVERAGE) run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t sqlite -c sysmon rules/ > /dev/null
$(COVERAGE) run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t csharp -c sysmon rules/ > /dev/null
$(COVERAGE) run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t logiq -c sysmon rules/ > /dev/null
+ $(COVERAGE) run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t sysmon -c sysmon -rvd rules/windows/driver_load rules/windows/file_event rules/windows/image_load rules/windows/network_connection rules/windows/process_access rules/windows/process_creation rules/windows/registry_event rules/windows/sysmon > /dev/null
$(COVERAGE) run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t splunk -c tools/config/splunk-windows-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-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-index.yml -f 'level>=high,level<=xcritical,status=stable,logsource=windows' rules/ > /dev/null
diff --git a/rules/windows/builtin/win_dcsync.yml b/rules/windows/builtin/win_dcsync.yml
index 5babb1379..cfe2bd114 100644
--- a/rules/windows/builtin/win_dcsync.yml
+++ b/rules/windows/builtin/win_dcsync.yml
@@ -3,8 +3,8 @@ id: 611eab06-a145-4dfa-a295-3ccc5c20f59a
description: Detects Mimikatz DC sync security events
status: experimental
date: 2018/06/03
-modified: 2019/10/08
-author: Benjamin Delpy, Florian Roth
+modified: 2020/09/11
+author: Benjamin Delpy, Florian Roth, Scott Dermott
references:
- https://twitter.com/gentilkiwi/status/1003236624925413376
- https://gist.github.com/gentilkiwi/dcc132457408cf11ad2061340dcb53c2
@@ -28,6 +28,7 @@ detection:
SubjectUserName:
- 'NT AUTHORITY*'
- '*$'
+ - 'MSOL_*'
condition: selection and not filter1 and not filter2
falsepositives:
- Valid DC Sync that is not covered by the filters; please report
diff --git a/rules/windows/builtin/win_disable_event_logging.yml b/rules/windows/builtin/win_disable_event_logging.yml
index da1f92fe0..52ef34e3f 100644
--- a/rules/windows/builtin/win_disable_event_logging.yml
+++ b/rules/windows/builtin/win_disable_event_logging.yml
@@ -6,7 +6,7 @@ references:
tags:
- attack.defense_evasion
- attack.t1054 # an old one
- - attack.t1562.006
+ - attack.t1562.002
author: '@neu5ron'
date: 2017/11/19
logsource:
diff --git a/rules/windows/other/win_defender_psexec_wmi_asr.yml b/rules/windows/other/win_defender_psexec_wmi_asr.yml
index 850023895..6761ba143 100644
--- a/rules/windows/other/win_defender_psexec_wmi_asr.yml
+++ b/rules/windows/other/win_defender_psexec_wmi_asr.yml
@@ -10,9 +10,8 @@ date: 2020/07/14
tags:
- attack.execution
- attack.lateral_movement
- - attack.t1570
- attack.t1047
- - attack.t1569
+ - attack.t1035 # an old one
- attack.t1569.002
logsource:
product: windows_defender
diff --git a/rules/windows/process_access/sysmon_invoke_phantom.yml b/rules/windows/process_access/sysmon_invoke_phantom.yml
index a389a9a56..bbcf116ae 100755
--- a/rules/windows/process_access/sysmon_invoke_phantom.yml
+++ b/rules/windows/process_access/sysmon_invoke_phantom.yml
@@ -10,7 +10,7 @@ references:
- https://twitter.com/timbmsft/status/900724491076214784
tags:
- attack.defense_evasion
- - attck.t1562.002
+ - attack.t1562.002
- attack.t1089 # an old one
logsource:
category: process_access
diff --git a/rules/windows/process_creation/win_etw_trace_evasion.yml b/rules/windows/process_creation/win_etw_trace_evasion.yml
index 84c4fa7b8..71bb05e64 100644
--- a/rules/windows/process_creation/win_etw_trace_evasion.yml
+++ b/rules/windows/process_creation/win_etw_trace_evasion.yml
@@ -11,7 +11,7 @@ date: 2019/03/22
tags:
- attack.defense_evasion
- attack.t1070
- - attack.t1562
+ - attack.t1562.006
- car.2016-04-002
level: high
logsource:
diff --git a/rules/windows/process_creation/win_susp_covenant.yml b/rules/windows/process_creation/win_susp_covenant.yml
index 40fa8950f..d2440ff5c 100644
--- a/rules/windows/process_creation/win_susp_covenant.yml
+++ b/rules/windows/process_creation/win_susp_covenant.yml
@@ -8,7 +8,9 @@ author: Florian Roth
date: 2020/06/04
tags:
- attack.execution
+ - attack.defense_evasion
- attack.t1059.001
+ - attack.t1564.003
- attack.t1086 # an old one
logsource:
category: process_creation
diff --git a/rules/windows/process_creation/win_susp_process_creations.yml b/rules/windows/process_creation/win_susp_process_creations.yml
deleted file mode 100644
index dd177e58c..000000000
--- a/rules/windows/process_creation/win_susp_process_creations.yml
+++ /dev/null
@@ -1,74 +0,0 @@
-title: Suspicious Process Creation
-id: 5f0f47a5-cb16-4dbe-9e31-e8d976d73de3
-status: experimental
-description: Detects suspicious process starts on Windows systems based on keywords
-author: Florian Roth, Daniil Yugoslavskiy, oscd.community (update)
-date: 2018/01/01
-modified: 2019/11/01
-references:
- - https://www.swordshield.com/2015/07/getting-hashes-from-ntds-dit-file/
- - https://www.youtube.com/watch?v=H3t_kHQG1Js&feature=youtu.be&t=15m35s
- - https://winscripting.blog/2017/05/12/first-entry-welcome-and-uac-bypass/
- - https://twitter.com/subTee/status/872244674609676288
- - https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/remote-tool-examples
- - https://tyranidslair.blogspot.ca/2017/07/dg-on-windows-10-s-executing-arbitrary.html
- - https://www.trustedsec.com/2017/07/new-tool-release-nps_payload/
- - https://subt0x10.blogspot.ca/2017/04/bypassing-application-whitelisting.html
- - https://gist.github.com/subTee/7937a8ef07409715f15b84781e180c46#file-rat-bat
- - https://twitter.com/vector_sec/status/896049052642533376
- - http://security-research.dyndns.org/pub/slides/FIRST-TC-2018/FIRST-TC-2018_Tom-Ueltschi_Sysmon_PUBLIC.pdf
-logsource:
- category: process_creation
- product: windows
-detection:
- selection:
- CommandLine:
- - '* sekurlsa:*'
- - net localgroup administrators * /add
- - net group "Domain Admins" * /ADD /DOMAIN
- - certutil.exe *-urlcache* http*
- - certutil.exe *-urlcache* ftp*
- - netsh advfirewall firewall *\AppData\\*
- - attrib +S +H +R *\AppData\\*
- - schtasks* /create *\AppData\\*
- - schtasks* /sc minute*
- - '*\Regasm.exe *\AppData\\*'
- - '*\Regasm *\AppData\\*'
- - '*\bitsadmin* /transfer*'
- - '*\certutil.exe * -decode *'
- - '*\certutil.exe * -decodehex *'
- - '*\certutil.exe -ping *'
- - icacls * /grant Everyone:F /T /C /Q
- - '* wbadmin.exe delete catalog -quiet*'
- - '*\wscript.exe *.jse'
- - '*\wscript.exe *.js'
- - '*\wscript.exe *.vba'
- - '*\wscript.exe *.vbe'
- - '*\cscript.exe *.jse'
- - '*\cscript.exe *.js'
- - '*\cscript.exe *.vba'
- - '*\cscript.exe *.vbe'
- - '*\fodhelper.exe'
- - '*waitfor*/s*'
- - '*waitfor*/si persist*'
- - '*remote*/s*'
- - '*remote*/c*'
- - '*remote*/q*'
- - '*AddInProcess*'
- - '* /stext *'
- - '* /scomma *'
- - '* /stab *'
- - '* /stabular *'
- - '* /shtml *'
- - '* /sverhtml *'
- - '* /sxml *'
- condition: selection
-fields:
- - ComputerName
- - User
- - CommandLine
-falsepositives:
- - False positives depend on scripts and administrative tools used in the monitored environment
-level: medium
-tags:
- - car.2013-07-001
\ No newline at end of file
diff --git a/rules/windows/registry_event/sysmon_susp_lsass_dll_load.yml b/rules/windows/registry_event/sysmon_susp_lsass_dll_load.yml
index bf440234b..e7ff37013 100644
--- a/rules/windows/registry_event/sysmon_susp_lsass_dll_load.yml
+++ b/rules/windows/registry_event/sysmon_susp_lsass_dll_load.yml
@@ -19,9 +19,9 @@ detection:
condition: selection
tags:
- attack.execution
+ - attack.persistence
- attack.t1177 # an old one
- attack.t1547.008
falsepositives:
- Unknown
level: high
-
diff --git a/tools/config/netwitness-epl.yml b/tools/config/netwitness-epl.yml
new file mode 100644
index 000000000..1709092b5
--- /dev/null
+++ b/tools/config/netwitness-epl.yml
@@ -0,0 +1,92 @@
+title: NetWitness
+order: 20
+backends:
+ - netwitness-epl
+logsources:
+ linux:
+ product: linux
+ conditions:
+ device.class: rhlinux
+ linux-sshd:
+ product: linux
+ service: sshd
+ conditions:
+ device.class: rhlinux
+ client: sshd
+ linux-auth:
+ product: linux
+ service: auth
+ conditions:
+ device.class: rhlinux
+ linux-clamav:
+ product: linux
+ service: clamav
+ conditions:
+ device.class: rhlinux
+ windows-sys:
+ product: windows
+ service: sysmon
+ conditions:
+ device.type: winevent_nic
+ event.source: microsoft-windows-security-auditing
+ windows-power:
+ product: windows
+ service: powershell
+ conditions:
+ device.type: winevent_nic
+ windows-dhcp:
+ product: windows
+ service: dhcp
+ conditions:
+ device.type: winevent_nic
+ event.source: microsoft-windows-dhcp-server
+ windows-sec:
+ product: windows
+ service: security
+ conditions:
+ device.type: winevent_nic
+ event.source: microsoft-windows-security-auditing
+ windows-system:
+ product: windows
+ service: system
+ conditions:
+ device.type: winevent_nic
+fieldmappings:
+ dst:
+ - ip.dst
+ dst_ip:
+ - ip.dst
+ src:
+ - ip.src
+ src_ip:
+ - ip.src
+ DestinationPort:
+ - ip.dstport
+ EventID:
+ - reference.id
+ NewProcessName:
+ - process
+ LogonType:
+ - logon.type
+ AccountName:
+ - user.dst
+ c-uri-extension:
+ - extension
+ c-useragent:
+ - user.agent
+ r-dns:
+ - alias.host
+ DestinationHostname:
+ - alias.host
+ cs-host:
+ - alias.host
+ c-uri-query:
+ - web.page
+ c-uri:
+ - web.page
+ cs-method:
+ - action
+ cs-cookie:
+ - web.cookie
+ SubjectUserName:
+ - user.dst
diff --git a/tools/sigma/backends/netwitness-epl.py b/tools/sigma/backends/netwitness-epl.py
new file mode 100644
index 000000000..e580b259c
--- /dev/null
+++ b/tools/sigma/backends/netwitness-epl.py
@@ -0,0 +1,163 @@
+# NetWitness EPL output backend for sigmac
+# Copyright 2019 Tarik BOUDJEMAA (@snake-jump)
+# Inspired from John Tuckner (@tuckner) NetWitness output backend for sigmac
+
+# NetWitness EPL backend for sigmac uses netwitness-epl.yml config file
+
+
+# RSA Alerts are generated by Event Processing Language (EPL) , that uses Esper Engine (https://www.espertech.com/esper/)
+# For more details see :https://community.rsa.com/docs/DOC-110246 and https://community.rsa.com/docs/DOC-80068
+
+# 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
+from sigma.parser.modifiers.base import SigmaTypeModifier
+from sigma.parser.modifiers.type import SigmaRegularExpressionModifier
+
+template="""
+module_XXXXX;
+@Name('RuleName')
+@RSAAlert(oneInSeconds=0)
+SELECT * FROM Event(
+
+EXPRESSION
+);"""
+
+class NetWitnessEplBackend(SingleTextQueryBackend):
+ """Converts Sigma rule into RSA NetWitness EPL . Contributed by @snake-jump"""
+ identifier = "netwitness-epl"
+ config_required = False
+ default_config = ["sysmon","netwitness-epl"]
+ active = True
+ reEscape = re.compile('(")')
+ #reEscape = re.compile("([\\|()\[\]{}.^$+])")
+ reClear = None
+ andToken = " AND "
+ orToken = " OR "
+ notToken = "NOT"
+ subExpression = "(%s)"
+ listExpression = "(%s)"
+ listSeparator = ", "
+ valueExpression = "\'%s\'"
+ keyExpression = "%s"
+ nullExpression = "%s exists"
+ notNullExpression = "%s exists"
+ mapExpression = "(%s=%s)"
+ mapListsSpecialHandling = True
+
+ def generateMapItemNode(self, node):
+ key, value = node
+ if type(key) != int:
+ key = key.replace(".","_") ## replace . by _ in meta name (RSA EPL)
+ key = key.lower()
+ 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[1:-1]:
+ value = re.sub('([".^$]|\\\\(?![*?]))', '\\\\\g<1>', value)
+ value = re.sub('\\*', '.*', value)
+ value = re.sub('\\?', '.', value)
+ return "(%s REGEXP %s)" %(key, self.generateValueNode(value))
+ elif type(value) == str and "*" in value:
+ value = re.sub("(\*\\\\)|(\*)", "", value)
+ value = self.generateValueNode("%"+value+"%") # add "%" to construct the like expression ex: process like %psexesvc%
+ return "(%s LIKE %s)" % (key,value)
+ elif type(value) in (str, int):
+ return self.mapExpression % (key, self.generateValueNode(value))
+ else:
+ return self.mapExpression % (key, self.generateNode(value))
+ elif type(value) == list:
+ return self.generateMapItemListNode(key, value)
+ elif value is None:
+ return self.nullExpression % (key, )
+
+ elif type(value) == SigmaRegularExpressionModifier: ## if value is regex
+ regex = str(value)
+ ## in RSA netwitness EPL regex each backslash must be escaped by backslash
+ ## ex : c:\temp\ to regex -> c:\\temp\\ to RSA EPL regex --> c:\\\\temp\\\\
+ regex = regex.replace("\\","\\\\")
+ # Regular Expressions have to match the full value in RSA Netwitness EPL
+ if not (regex.startswith('^') or regex.startswith('.*')):
+ regex = '.*' + regex
+ if not (regex.endswith('$') or regex.endswith('.*')):
+ regex = regex + '.*'
+ return "(%s REGEXP %s)" %(key, self.generateValueNode(regex))
+ else:
+ raise TypeError("Backend does not support map values of type " + str(type(value)))
+
+ def generateMapItemListNode(self, key, value):
+ equallist = list()
+ containlist = list()
+ regexlist = list()
+ for item in value:
+ if type(item) == str and "*" in item[1:-1]:
+ item = re.sub('([".^$]|\\\\(?![*?]))', '\\\\\g<1>', item)
+ item = re.sub('\\*', '.*', item)
+ item = re.sub('\\?', '.', item)
+ regexlist.append(self.generateValueNode(item))
+ elif type(item) == str and (item.endswith("*") or item.startswith("*")):
+ item_temp=item
+ item = re.sub("(\*\\\\)|(\*)", "", item)
+ if item_temp.endswith("*") and item_temp.startswith("*"): # pattern begins with "*" and ends with "*"
+ containlist.append(self.generateValueNode('%'+item+'%')) # add "%" to construct the like expression ex: process like %psexesvc%
+ elif item_temp.startswith("*"): # pattern don't end with "*"
+ containlist.append(self.generateValueNode('%'+item))
+ else: # item_temp.endswith("*") pattern don't begin with "*"
+ containlist.append(self.generateValueNode(item+'%'))
+ else:
+ equallist.append(self.generateValueNode(item))
+ fmtitems = list()
+ if equallist:
+ if len(equallist) == 1:
+ fmtitems.append("%s = %s" % (key, ", ".join(equallist)))
+ else:
+ # add "(" and ")" to the first and the last item from the list to have meta_key IN ('value1','value2')
+ equallist[0]=("("+equallist[0])
+ equallist[-1]=(equallist[-1]+")")
+ fmtitems.append("%s IN %s" % (key, ", ".join(equallist)))
+
+ if containlist:
+ fmtitems.append("%s LIKE %s" % (key, (" OR "+key+" LIKE ").join(containlist)))
+ if regexlist:
+ fmtitems.append("%s REGEXP %s" % (key, "|".join(regexlist)))
+ fmtquery = "("+" OR ".join(filter(None, fmtitems))
+ # Delete the " ' " from the begin or the end of each regex pattern ex : '.*('patern1'|'patern2').*' --> '.*(patern1|patern2).*'
+ fmtquery = re.sub('\'\.\*\(\'','\'.*(',fmtquery)
+ fmtquery = re.sub('\'\)\.\*\'',').*\'',fmtquery)
+ fmtquery = re.sub('\'\|\'','|',fmtquery)
+ fmtquery = fmtquery+')'
+ return fmtquery
+
+ def generateValueNode(self, node):
+ return self.valueExpression % (str(node))
+
+ 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, sigmaparser)
+ query=query.replace('INDEX','`index`') # index is reserved keyword in Esper and must be escaped
+ query=template.replace('EXPRESSION', query)
+ try:
+ query=query.replace('RuleName', sigmaparser.parsedyaml["title"].replace(" ","")) # add rule name
+ query=query.replace('module_XXXXX', "module "+sigmaparser.parsedyaml["title"].replace(" ","")) # add rule name
+ except:
+ print("Error when replacing RuleName by Title from yaml")
+ pass
+ return query
+
+ def generateQuery(self, parsed, sigmaparser):
+ result = self.generateNode(parsed.parsedSearch)
+ return result
diff --git a/tools/sigma/backends/sysmon.py b/tools/sigma/backends/sysmon.py
new file mode 100644
index 000000000..12171dc34
--- /dev/null
+++ b/tools/sigma/backends/sysmon.py
@@ -0,0 +1,244 @@
+import re
+
+import sigma
+from sigma.backends.base import SingleTextQueryBackend
+from sigma.backends.mixins import MultiRuleOutputMixin
+
+from .exceptions import NotSupportedError
+
+
+class SysmonConfigBackend(SingleTextQueryBackend, MultiRuleOutputMixin):
+ identifier = "sysmon"
+ active = True
+ andToken = " AND "
+ orToken = " OR "
+ notToken = "NOT "
+ subExpression = "(%s)"
+ config_required = False
+ INCLUDE = "include"
+ EXCLUDE = "exclude"
+ conditionDict = {
+ "startswith": "begin with",
+ "endswith": "end with",
+ }
+
+ def __init__(self, *args, **kwargs):
+ self.table = None
+ self.logsource = None
+ self.allowedSource = {
+ "process_creation": "ProcessCreate"
+ }
+ self.eventidTagMapping = {
+ 1: "ProcessCreate",
+ 4799: "ProcessCreate",
+ 2: "FileCreateTime",
+ 3: "NetworkConnect",
+ 5: "ProcessTerminate",
+ 6: "DriverLoad",
+ 7: "ImageLoad",
+ 8: "CreateRemoteThread",
+ 9: "RawAccessRead",
+ 10: "ProcessAccess",
+ 11: "FileCreate",
+ 12: "RegistryEvent",
+ 13: "RegistryEvent",
+ 14: "RegistryEvent",
+ 15: "FileCreateStreamHash",
+ 17: "PipeEvent",
+ 18: "PipeEvent",
+ 19: "WmiEvent",
+ 20: "WmiEvent",
+ 21: "WmiEvent",
+ 22: "DNSQuery",
+ 257: "DNSQuery",
+ 23: "FileDelete"
+ }
+ self.allowedCondCombinations = {
+ 'single': [
+ [4],
+ [1, 4],
+ [2, 4],
+ ],
+ 'multi': [
+ [1, 2, 4],
+ ],
+ "exclude": [
+ [1, 3, 4],
+ [2, 3, 4]
+ ],
+ # "multi-exclude": [
+ # [1, 2, 3, 4]
+ # ]
+ }
+ return super().__init__(*args, **kwargs)
+
+ def cleanValue(self, value):
+ val = re.sub("[*]", "", value)
+ return val
+
+ def mapFiledValue(self, field, value):
+ condition = None
+ if "|" in field:
+ field, *pipes = field.split("|")
+ if len(pipes) == 1:
+ condition = pipes[0]
+ else:
+ raise NotImplementedError("not implemented condition")
+ if isinstance(value, list) and len(value) > 1:
+ condition = "contains any"
+ value = ";".join(value)
+ elif "*" in value:
+ if value.startswith("*") and value.endswith("*"):
+ condition = "contains"
+ elif value.startswith("*"):
+ condition = "end with"
+ elif value.endswith("*"):
+ condition = "begin with"
+ else:
+ condition = "contains"
+
+ if condition:
+ field_str = '<{field} condition="{condition}">{value}{field}>'.format(field=field,
+ condition=condition,
+ value=self.cleanValue(value))
+ else:
+ field_str = '<{field}>{value}{field}>'.format(field=field, value=self.cleanValue(value))
+
+ return field_str
+
+ def createRule(self, selections):
+ fields_list = []
+ table = None
+ for field, value in selections.items():
+ if isinstance(value, list) and len(value) == 1:
+ value = value[0]
+ if field == "EventID":
+ try:
+ table = self.eventidTagMapping[value]
+ except KeyError:
+ table = self.eventidTagMapping[1]
+ else:
+ created_field_value = self.mapFiledValue(field, value)
+ fields_list.append(created_field_value)
+ fields_list_filtered = [item for item in fields_list if item]
+ if any(fields_list_filtered):
+ rule = '''\n\t\t\n\t\t\t{fields}\n\t\t'''.format(rule_name=self.rule_name, fields="\n\t\t\t".join(["{}".format(item) for item in fields_list_filtered]))
+ t = table if table else self.table
+ return rule, t
+ else:
+ return None, None
+
+ def createRuleGroup(self, condition_objects, condition, match_type="include"):
+ rules = None
+ rules_selections = [item for item in condition_objects if item.type == 4]
+ if len(rules_selections) == 1:
+ rule, table = self.createRule(self.detection.get(rules_selections[0].matched))
+ rules = {match_type: {table: rule}}
+ else:
+ if "or" in condition.lower():
+ result = {}
+ for selection_object in rules_selections:
+ rule, table = self.createRule(self.detection.get(selection_object.matched))
+ if result.get(table):
+ result[table].append(rule)
+ else:
+ result[table] = [rule]
+ result = {table_name: "\n\t\t".join(rules_list) for table_name, rules_list in result.items()}
+ rules = {match_type: result}
+ elif "and" in condition.lower():
+ rules_dict = {}
+ for selection_object in rules_selections:
+ rules_dict.update(self.detection.get(selection_object.matched))
+ rule, table = self.createRule(rules_dict)
+ rules = {match_type: {table: rule}}
+ if rules:
+ rules_result = []
+ for match, tables in rules.items():
+ for table, rules in tables.items():
+ category_comment = '\n\n{}'.format(table, match,
+ "".join(rules))
+ rules_result.append(category_comment)
+ return "".join(rules_result)
+ else:
+ raise NotSupportedError("Couldn't create rule with current condition.")
+
+ def createMultiRuleGroup(self, conditions):
+ conditions_id = "".join([str(item.type) for item in conditions])
+ or_index = conditions_id.index("2")
+ sorted_conditions = [conditions[:or_index], conditions[or_index+1:]]
+ if sorted_conditions:
+ result = ""
+ for rule_condition in sorted_conditions:
+ rule = self.createRuleGroup(condition_objects=rule_condition, condition=" ".join([item.matched for item in rule_condition]))
+ result += "{}\n".format(rule)
+ return result
+ else:
+ raise NotSupportedError("Not implemented condition.")
+
+ def createExcludeRuleGroup(self, conditions):
+ conditions_id = "".join([str(item.type) for item in conditions])
+ condition = self.detection.get("condition")
+ sorted_conditions = None
+ if "and not" in condition.lower():
+ andnot_index = conditions_id.index("13")
+ sorted_conditions = [(conditions[:andnot_index], self.INCLUDE), ([item for item in conditions if item.type != 3], self.EXCLUDE)]
+ elif "or not" in condition.lower():
+ ornot_index = conditions_id.index("23")
+ sorted_conditions = [(conditions[:ornot_index], self.INCLUDE), (conditions[ornot_index + 2:], self.EXCLUDE)]
+ if sorted_conditions:
+ result = ""
+ for rule_condition in sorted_conditions:
+ rule = self.createRuleGroup(condition_objects=rule_condition[0], condition=" ".join([item.matched for item in rule_condition[0]]), match_type=rule_condition[1])
+ result += "{}\n".format(rule)
+ return result
+
+ def checkRuleCondition(self, condtokens):
+ if len(condtokens) == 1:
+ conditions = [item for item in condtokens[0].tokens]
+ conditions_combination = list(set([item.type for item in conditions]))
+ for rule_type, combinations in self.allowedCondCombinations.items():
+ for combination in combinations:
+ if sorted(conditions_combination) == sorted(combination):
+ return rule_type, conditions
+ else:
+ raise NotSupportedError("Not supported condition.")
+ else:
+ raise NotSupportedError("Not supported condition.")
+
+ def createTableFromLogsource(self):
+ if self.logsource.get("product", "") != "windows":
+ raise NotSupportedError(
+ "Not supported logsource. Should be product `windows`.")
+ for item in self.logsource.values():
+ if item.lower() in self.allowedSource.keys():
+ self.table = self.allowedSource.get(item.lower())
+ break
+ else:
+ self.table = "ProcessCreate"
+
+ def checkDetection(self):
+ for selection_name, value in self.detection.items():
+ if isinstance(value, list):
+ raise NotSupportedError("Keywords are not supported in sysmon backend.")
+
+
+ def generate(self, sigmaparser):
+ sysmon_rule = None
+ title = sigmaparser.parsedyaml.get("title", "")
+ author = sigmaparser.parsedyaml.get("author", {})
+ self.rule_name = "{} by {}".format(title, author)
+ self.detection = sigmaparser.parsedyaml.get("detection", {})
+ self.checkDetection()
+ self.logsource = sigmaparser.parsedyaml["logsource"]
+ self.createTableFromLogsource()
+ rule_type, conditions = self.checkRuleCondition(sigmaparser.condtoken)
+ if rule_type == "single":
+ sysmon_rule = self.createRuleGroup(conditions, self.detection.get("condition"))
+ elif rule_type == "multi":
+ sysmon_rule = self.createMultiRuleGroup(conditions)
+ elif rule_type == "exclude":
+ sysmon_rule = self.createExcludeRuleGroup(conditions)
+
+ if sysmon_rule:
+ rulegroup_comment = ''
+ return "{}\n{}".format(rulegroup_comment, sysmon_rule)
\ No newline at end of file