mirror of
https://github.com/valitydev/SigmaHQ.git
synced 2024-11-06 09:25:17 +00:00
we
This commit is contained in:
commit
da9b32bdd6
2
Makefile
2
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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -19,9 +19,9 @@ detection:
|
||||
condition: selection
|
||||
tags:
|
||||
- attack.execution
|
||||
- attack.persistence
|
||||
- attack.t1177 # an old one
|
||||
- attack.t1547.008
|
||||
falsepositives:
|
||||
- Unknown
|
||||
level: high
|
||||
|
||||
|
92
tools/config/netwitness-epl.yml
Normal file
92
tools/config/netwitness-epl.yml
Normal file
@ -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
|
163
tools/sigma/backends/netwitness-epl.py
Normal file
163
tools/sigma/backends/netwitness-epl.py
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
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
|
244
tools/sigma/backends/sysmon.py
Normal file
244
tools/sigma/backends/sysmon.py
Normal file
@ -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<Rule name="{rule_name}" groupRelation="and">\n\t\t\t{fields}\n\t\t</Rule>'''.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<!--Insert This Rule in <{} onmatch="{}"> section -->\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 = '<!--RuleGroup groupRelation should be `or` <RuleGroup groupRelation="or"> -->'
|
||||
return "{}\n{}".format(rulegroup_comment, sysmon_rule)
|
Loading…
Reference in New Issue
Block a user