mirror of
https://github.com/valitydev/SigmaHQ.git
synced 2024-11-08 02:08:54 +00:00
Merge remote-tracking branch 'Neo23x0/master'
This commit is contained in:
commit
923f298015
1
_config.yml
Normal file
1
_config.yml
Normal file
@ -0,0 +1 @@
|
||||
theme: jekyll-theme-hacker
|
17
rules/apt/apt_stonedrill.yml
Normal file
17
rules/apt/apt_stonedrill.yml
Normal file
@ -0,0 +1,17 @@
|
||||
title: StoneDrill Service Install
|
||||
description: 'This method detects a service install of the malicious Microsoft Network Realtime Inspection Service service described in StoneDrill report by Kaspersky'
|
||||
author: Florian Roth
|
||||
reference: https://securelist.com/blog/research/77725/from-shamoon-to-stonedrill/
|
||||
logsource:
|
||||
product: windows
|
||||
service: system
|
||||
detection:
|
||||
selection:
|
||||
EventID: 7045
|
||||
indicators:
|
||||
- ServiceName: NtsSrv
|
||||
- ServiceFileName: '* LocalService'
|
||||
condition: selection and indicators
|
||||
falsepositives:
|
||||
- Unlikely
|
||||
level: high
|
@ -4,12 +4,6 @@ author: Florian Roth
|
||||
logsource:
|
||||
product: windows
|
||||
detection:
|
||||
selection:
|
||||
EventLog:
|
||||
- Security
|
||||
- System
|
||||
- Application
|
||||
- Microsoft-Windows-Sysmon/Operational
|
||||
keywords:
|
||||
- mimikatz
|
||||
- mimilib
|
||||
@ -19,7 +13,7 @@ detection:
|
||||
- sekurlsa::logonpasswords
|
||||
- lsadump::sam
|
||||
- mimidrv.sys
|
||||
condition: selection and 1 of keywords
|
||||
condition: keywords
|
||||
falsepositives:
|
||||
- Naughty administrators
|
||||
- Penetration test
|
||||
|
@ -3,9 +3,8 @@ description: This detection method points out highly relevant Antivirus events
|
||||
author: Florian Roth
|
||||
logsource:
|
||||
product: windows
|
||||
service: application
|
||||
detection:
|
||||
selection:
|
||||
EventLog: Application
|
||||
keywords:
|
||||
- HTool
|
||||
- Hacktool
|
||||
@ -30,7 +29,7 @@ detection:
|
||||
filters:
|
||||
- Keygen
|
||||
- Crack
|
||||
condition: selection and 1 of keywords and not 1 of filters
|
||||
condition: keywords and not 1 of filters
|
||||
falsepositives:
|
||||
- Some software piracy tools (key generators, cracks) are classified as hack tools
|
||||
level: high
|
||||
|
22
rules/windows/builtin/win_malicious_service_install.yml
Normal file
22
rules/windows/builtin/win_malicious_service_install.yml
Normal file
@ -0,0 +1,22 @@
|
||||
title: Malicious Service Install
|
||||
description: This method detects well-known keywords of malicious services in the Windows System Eventlog
|
||||
author: Florian Roth
|
||||
logsource:
|
||||
product: windows
|
||||
service: system
|
||||
detection:
|
||||
selection:
|
||||
EventID:
|
||||
- 7045
|
||||
- 4697
|
||||
keywords:
|
||||
- 'WCE SERVICE'
|
||||
- 'WCESERVICE'
|
||||
- 'DumpSvc'
|
||||
quarkspwdump:
|
||||
EventID: 16
|
||||
HiveName: '*\AppData\Local\Temp\SAM*.dmp'
|
||||
condition: ( selection and keywords ) or quarkspwdump
|
||||
falsepositives:
|
||||
- Unlikely
|
||||
level: high
|
16
rules/windows/builtin/win_rare_service_installs.yml
Normal file
16
rules/windows/builtin/win_rare_service_installs.yml
Normal file
@ -0,0 +1,16 @@
|
||||
title: Rare Service Installs
|
||||
description: Detects rare service installs that only appear a few times per timeframe and could reveal password dumpers, backdoor installs or other types of malicious services
|
||||
status: experimental
|
||||
author: Florian Roth
|
||||
logsource:
|
||||
product: windows
|
||||
service: system
|
||||
detection:
|
||||
selection:
|
||||
EventID: 7045
|
||||
timeframe: 7d
|
||||
condition: selection | count(ServiceFileName) < 5
|
||||
falsepositives:
|
||||
- Software installation
|
||||
- Software updates
|
||||
level: low
|
@ -5,9 +5,9 @@ reference: https://adsecurity.org/?p=1772
|
||||
author: Thomas Patzke
|
||||
logsource:
|
||||
product: windows
|
||||
service: security
|
||||
detection:
|
||||
selection:
|
||||
EventLog: Security
|
||||
EventID:
|
||||
- 4765
|
||||
- 4766
|
||||
|
@ -5,9 +5,9 @@ reference: https://adsecurity.org/?p=1714
|
||||
author: Thomas Patzke
|
||||
logsource:
|
||||
product: windows
|
||||
service: security
|
||||
detection:
|
||||
selection:
|
||||
EventLog: Security
|
||||
EventID: 4794
|
||||
condition: selection
|
||||
falsepositives:
|
||||
|
@ -4,9 +4,9 @@ reference: https://twitter.com/deviouspolack/status/832535435960209408
|
||||
author: Florian Roth
|
||||
logsource:
|
||||
product: windows
|
||||
service: system
|
||||
detection:
|
||||
selection:
|
||||
EventLog: System
|
||||
EventID: 104
|
||||
condition: selection
|
||||
falsepositives:
|
||||
|
@ -3,9 +3,9 @@ description: This method uses uncommon error codes on failed logons to determine
|
||||
author: Florian Roth
|
||||
logsource:
|
||||
product: windows
|
||||
service: security
|
||||
detection:
|
||||
selection:
|
||||
EventLog: Security
|
||||
EventID:
|
||||
- 4625
|
||||
- 4776
|
||||
|
@ -3,9 +3,9 @@ description: Detects suspicious failed logins with different user accounts from
|
||||
author: Florian Roth
|
||||
logsource:
|
||||
product: windows
|
||||
service: security
|
||||
detection:
|
||||
selection:
|
||||
EventLog: Security
|
||||
EventID:
|
||||
- 529
|
||||
- 4625
|
||||
|
@ -3,9 +3,9 @@ description: This method triggers on rare Kerberos Failure Codes caused by manip
|
||||
author: Florian Roth
|
||||
logsource:
|
||||
product: windows
|
||||
service: security
|
||||
detection:
|
||||
selection:
|
||||
EventLog: Security
|
||||
EventID:
|
||||
- 675
|
||||
- 4768
|
||||
|
@ -4,9 +4,9 @@ status: experimental
|
||||
reference: https://twitter.com/jackcr/status/807385668833968128
|
||||
logsource:
|
||||
product: windows
|
||||
service: security
|
||||
detection:
|
||||
selection:
|
||||
EventLog: Security
|
||||
EventID: 4656
|
||||
ProcessName: 'C:\Windows\System32\lsass.exe'
|
||||
AccessMask: '0x705'
|
||||
|
@ -4,9 +4,9 @@ reference: https://adsecurity.org/?p=3458
|
||||
description: Detects logons using RC4 encryption type
|
||||
logsource:
|
||||
product: windows
|
||||
service: security
|
||||
detection:
|
||||
selection:
|
||||
EventLog: Security
|
||||
EventID: 4769
|
||||
TicketOptions: '0x40810000'
|
||||
TicketEncryption: '0x17'
|
||||
|
24
rules/windows/builtin/win_susp_recon_activity.yml
Normal file
24
rules/windows/builtin/win_susp_recon_activity.yml
Normal file
@ -0,0 +1,24 @@
|
||||
title: Detects Reconnaissance Activity
|
||||
status: experimental
|
||||
description: 'Detects activity as "net user administrator /domain" and "net group domain admins /domain"'
|
||||
reference: https://findingbad.blogspot.de/2017/01/hunting-what-does-it-look-like.html
|
||||
author: Florian Roth (rule), Jack Croock (method)
|
||||
logsource:
|
||||
product: windows
|
||||
service: security
|
||||
description: The volume of Event ID 4661 ist high on Domain Controllers and therefore "Audit SAM" and "Audit Kernel Object" advanced audit policy settings are not configured in the recommandations for server systems
|
||||
detection:
|
||||
selection:
|
||||
- EventID: 4661
|
||||
ObjectType: 'SAM_USER'
|
||||
ObjectName: 'S-1-5-21-*-500'
|
||||
AccessMask: '0x2d'
|
||||
- EventID: 4661
|
||||
ObjectType: 'SAM_GROUP'
|
||||
ObjectName: 'S-1-5-21-*-512'
|
||||
AccessMask: '0x2d'
|
||||
condition: selection
|
||||
falsepositives:
|
||||
- Administrator activity
|
||||
- Penetration tests
|
||||
level: high
|
@ -3,9 +3,9 @@ description: Some threat groups tend to delete the local 'Security' Eventlog usi
|
||||
author: Florian Roth
|
||||
logsource:
|
||||
product: windows
|
||||
service: security
|
||||
detection:
|
||||
selection:
|
||||
EventLog: Security
|
||||
EventID:
|
||||
- 517
|
||||
- 1102
|
||||
|
21
rules/windows/powershell/powershell_exe_calling_ps.yml
Normal file
21
rules/windows/powershell/powershell_exe_calling_ps.yml
Normal file
@ -0,0 +1,21 @@
|
||||
title: PowerShell called from an Executable Version Mismatch
|
||||
status: experimental
|
||||
description: Detects PowerShell called from an executable by the version mismatch method
|
||||
reference: https://adsecurity.org/?p=2921
|
||||
author: Sean Metcalf (source), Florian Roth (rule)
|
||||
logsource:
|
||||
platform: windows
|
||||
product: powershell
|
||||
description: 'It is recommanded to use the new "Script Block Logging" of PowerShell v5 https://adsecurity.org/?p=2277'
|
||||
detection:
|
||||
selection1:
|
||||
EventID: 400
|
||||
EngineVersion:
|
||||
- '2.*'
|
||||
- '4.*'
|
||||
- '5.*'
|
||||
HostVersion: '3.*'
|
||||
condition: selection1
|
||||
falsepositives:
|
||||
- Pentesters
|
||||
level: high
|
121
rules/windows/powershell/powershell_malicious_commandlets.yml
Normal file
121
rules/windows/powershell/powershell_malicious_commandlets.yml
Normal file
@ -0,0 +1,121 @@
|
||||
title: Malicious PowerShell Commandlets
|
||||
status: experimental
|
||||
description: Detects Commandlet names from well-known PowerShell exploitation frameworks
|
||||
reference: https://adsecurity.org/?p=2921
|
||||
author: Sean Metcalf (source), Florian Roth (rule)
|
||||
logsource:
|
||||
platform: windows
|
||||
product: powershell
|
||||
description: 'It is recommanded to use the new "Script Block Logging" of PowerShell v5 https://adsecurity.org/?p=2277'
|
||||
detection:
|
||||
keywords:
|
||||
- Invoke-DllInjection
|
||||
- Invoke-Shellcode
|
||||
- Invoke-WmiCommand
|
||||
- Get-GPPPassword
|
||||
- Get-Keystrokes
|
||||
- Get-TimedScreenshot
|
||||
- Get-VaultCredential
|
||||
- Invoke-CredentialInjection
|
||||
- Invoke-Mimikatz
|
||||
- Invoke-NinjaCopy
|
||||
- Invoke-TokenManipulation
|
||||
- Out-Minidump
|
||||
- VolumeShadowCopyTools
|
||||
- Invoke-ReflectivePEInjection
|
||||
- Invoke-UserHunter
|
||||
- Find-GPOLocation
|
||||
- Invoke-ACLScanner
|
||||
- Invoke-DowngradeAccount
|
||||
- Get-ServiceUnquoted
|
||||
- Get-ServiceFilePermission
|
||||
- Get-ServicePermission
|
||||
- Invoke-ServiceAbuse
|
||||
- Install-ServiceBinary
|
||||
- Get-RegAutoLogon
|
||||
- Get-VulnAutoRun
|
||||
- Get-VulnSchTask
|
||||
- Get-UnattendedInstallFile
|
||||
- Get-WebConfig
|
||||
- Get-ApplicationHost
|
||||
- Get-RegAlwaysInstallElevated
|
||||
- Get-Unconstrained
|
||||
- Add-RegBackdoor
|
||||
- Add-ScrnSaveBackdoor
|
||||
- Gupt-Backdoor
|
||||
- Invoke-ADSBackdoor
|
||||
- Enabled-DuplicateToken
|
||||
- Invoke-PsUaCme
|
||||
- Remove-Update
|
||||
- Check-VM
|
||||
- Get-LSASecret
|
||||
- Get-PassHashes
|
||||
- Invoke-Mimikatz
|
||||
- Show-TargetScreen
|
||||
- Port-Scan
|
||||
- Invoke-PoshRatHttp
|
||||
- Invoke-PowerShellTCP
|
||||
- Invoke-PowerShellWMI
|
||||
- Add-Exfiltration
|
||||
- Add-Persistence
|
||||
- Do-Exfiltration
|
||||
- Start-CaptureServer
|
||||
- Invoke-DllInjection
|
||||
- Invoke-ReflectivePEInjection
|
||||
- Invoke-ShellCode
|
||||
- Get-ChromeDump
|
||||
- Get-ClipboardContents
|
||||
- Get-FoxDump
|
||||
- Get-IndexedItem
|
||||
- Get-Keystrokes
|
||||
- Get-Screenshot
|
||||
- Invoke-Inveigh
|
||||
- Invoke-NetRipper
|
||||
- Invoke-NinjaCopy
|
||||
- Out-Minidump
|
||||
- Invoke-EgressCheck
|
||||
- Invoke-PostExfil
|
||||
- Invoke-PSInject
|
||||
- Invoke-RunAs
|
||||
- MailRaider
|
||||
- New-HoneyHash
|
||||
- Set-MacAttribute
|
||||
- Get-VaultCredential
|
||||
- Invoke-DCSync
|
||||
- Invoke-Mimikatz
|
||||
- Invoke-PowerDump
|
||||
- Invoke-TokenManipulation
|
||||
- Exploit-Jboss
|
||||
- Invoke-ThunderStruck
|
||||
- Invoke-VoiceTroll
|
||||
- Set-Wallpaper
|
||||
- Invoke-InveighRelay
|
||||
- Invoke-PsExec
|
||||
- Invoke-SSHCommand
|
||||
- Get-SecurityPackages
|
||||
- Install-SSP
|
||||
- Invoke-BackdoorLNK
|
||||
- PowerBreach
|
||||
- Get-GPPPassword
|
||||
- Get-SiteListPassword
|
||||
- Get-System
|
||||
- Invoke-BypassUAC
|
||||
- Invoke-Tater
|
||||
- Invoke-WScriptBypassUAC
|
||||
- PowerUp
|
||||
- PowerView
|
||||
- Get-RickAstley
|
||||
- Find-Fruit
|
||||
- HTTP-Login
|
||||
- Find-TrustedDocuments
|
||||
- Invoke-Paranoia
|
||||
- Invoke-WinEnum
|
||||
- Invoke-ARPScan
|
||||
- Invoke-PortScan
|
||||
- Invoke-ReverseDNSLookup
|
||||
- Invoke-SMBScanner
|
||||
- Invoke-Mimikittenz
|
||||
condition: keywords
|
||||
falsepositives:
|
||||
- Penetration testing
|
||||
level: high
|
41
rules/windows/powershell/powershell_malicious_keywords.yml
Normal file
41
rules/windows/powershell/powershell_malicious_keywords.yml
Normal file
@ -0,0 +1,41 @@
|
||||
title: Malicious PowerShell Commandlets
|
||||
status: experimental
|
||||
description: Detects Commandlet names from well-known PowerShell exploitation frameworks
|
||||
reference: https://adsecurity.org/?p=2921
|
||||
author: Sean Metcalf (source), Florian Roth (rule)
|
||||
logsource:
|
||||
platform: windows
|
||||
product: powershell
|
||||
description: 'It is recommanded to use the new "Script Block Logging" of PowerShell v5 https://adsecurity.org/?p=2277'
|
||||
detection:
|
||||
keywords:
|
||||
- AdjustTokenPrivileges
|
||||
- IMAGE_NT_OPTIONAL_HDR64_MAGIC
|
||||
- Management.Automation.RuntimeException
|
||||
- Microsoft.Win32.UnsafeNativeMethods
|
||||
- ReadProcessMemory.Invoke
|
||||
- Runtime.InteropServices
|
||||
- SE_PRIVILEGE_ENABLED
|
||||
- System.Security.Cryptography
|
||||
- System.Runtime.InteropServices
|
||||
- LSA_UNICODE_STRING
|
||||
- MiniDumpWriteDump
|
||||
- PAGE_EXECUTE_READ
|
||||
- Net.Sockets.SocketFlags
|
||||
- Reflection.Assembly
|
||||
- SECURITY_DELEGATION
|
||||
- TOKEN_ADJUST_PRIVILEGES
|
||||
- TOKEN_ALL_ACCESS
|
||||
- TOKEN_ASSIGN_PRIMARY
|
||||
- TOKEN_DUPLICATE
|
||||
- TOKEN_ELEVATION
|
||||
- TOKEN_IMPERSONATE
|
||||
- TOKEN_INFORMATION_CLASS
|
||||
- TOKEN_PRIVILEGES
|
||||
- TOKEN_QUERY
|
||||
- Metasploit
|
||||
- Mimikatz
|
||||
condition: keywords
|
||||
falsepositives:
|
||||
- Penetration tests
|
||||
level: high
|
17
rules/windows/powershell/powershell_psattack.yml
Normal file
17
rules/windows/powershell/powershell_psattack.yml
Normal file
@ -0,0 +1,17 @@
|
||||
title: PowerShell PSAttack
|
||||
status: experimental
|
||||
description: Detects the use of PSAttack PowerShell hack tool
|
||||
reference: https://adsecurity.org/?p=2921
|
||||
author: Sean Metcalf (source), Florian Roth (rule)
|
||||
logsource:
|
||||
platform: windows
|
||||
product: powershell
|
||||
description: 'It is recommanded to use the new "Script Block Logging" of PowerShell v5 https://adsecurity.org/?p=2277'
|
||||
detection:
|
||||
EventID: 4103
|
||||
keywords:
|
||||
- 'PS ATTACK!!!'
|
||||
condition: keywords
|
||||
falsepositives:
|
||||
- Pentesters
|
||||
level: high
|
15
rules/windows/powershell/powershell_suspicious_download.yml
Normal file
15
rules/windows/powershell/powershell_suspicious_download.yml
Normal file
@ -0,0 +1,15 @@
|
||||
title: Suspicious PowerShell Download
|
||||
status: experimental
|
||||
description: Detects suspicious PowerShell download command
|
||||
author: Florian Roth
|
||||
logsource:
|
||||
platform: windows
|
||||
product: powershell
|
||||
detection:
|
||||
keywords:
|
||||
- 'System.Net.WebClient).DownloadString('
|
||||
- 'system.net.webclient).downloadfile('
|
||||
condition: keywords
|
||||
falsepositives:
|
||||
- PowerShell scripts that download content from the Internet
|
||||
level: medium
|
@ -0,0 +1,19 @@
|
||||
title: Suspicious PowerShell Invocations
|
||||
status: experimental
|
||||
description: Detects suspicious PowerShell invocation command parameters
|
||||
author: Florian Roth (rule)
|
||||
logsource:
|
||||
platform: windows
|
||||
product: powershell
|
||||
detection:
|
||||
keywords:
|
||||
- ' -nop -w hidden -c * [Convert]::FromBase64String'
|
||||
- ' -w hidden -noni -nop -c "iex(New-Object'
|
||||
- ' -w hidden -ep bypass -Enc'
|
||||
- 'powershell.exe reg add HKCU\software\microsoft\windows\currentversion\run'
|
||||
- 'bypass -noprofile -windowstyle hidden (new-object system.net.webclient).download'
|
||||
- 'iex(New-Object Net.WebClient).Download'
|
||||
condition: keywords
|
||||
falsepositives:
|
||||
- Penetration tests
|
||||
level: high
|
@ -1,4 +1,4 @@
|
||||
title: MSHTA Spawning Windows Shell
|
||||
title: MSHTA Spawning Windows Shell
|
||||
status: experimental
|
||||
description: Detects a Windows command line executable started from MSHTA.
|
||||
reference: https://www.trustedsec.com/july-2015/malicious-htas/
|
||||
|
@ -0,0 +1,18 @@
|
||||
title: Suspicious PowerShell Parameter Combination
|
||||
status: experimental
|
||||
description: Detects suspicious PowerShell invocation command parameters
|
||||
author: Florian Roth
|
||||
logsource:
|
||||
product: sysmon
|
||||
detection:
|
||||
keywords:
|
||||
- 'powershell'
|
||||
- ' -nop '
|
||||
- ' -w hidden '
|
||||
- ' -exec bypass '
|
||||
- ' -enc '
|
||||
condition: all of keywords
|
||||
falsepositives:
|
||||
- Penetration tests
|
||||
- Very special / sneaky PowerShell scripts
|
||||
level: high
|
@ -1,3 +1,3 @@
|
||||
Tools in this section are currently in public beta status.
|
||||
|
||||
The ```--config``` and ```--recurse``` parameters are not usable yet.
|
||||
The ```--output``` and ```--config``` parameters are not usable yet.
|
||||
|
@ -22,6 +22,11 @@ class BaseBackend:
|
||||
identifier = "base"
|
||||
active = False
|
||||
|
||||
def __init__(self, sigmaconfig):
|
||||
if not isinstance(sigmaconfig, (sigma.SigmaConfiguration, None)):
|
||||
raise TypeError("SigmaConfiguration object expected")
|
||||
self.sigmaconfig = sigmaconfig
|
||||
|
||||
def generate(self, parsed):
|
||||
return self.generateNode(parsed.getParseTree())
|
||||
|
||||
@ -96,7 +101,7 @@ class ElasticsearchQuerystringBackend(BaseBackend):
|
||||
key, value = node
|
||||
if type(value) not in (str, int, list):
|
||||
raise TypeError("Map values must be strings, numbers or lists, not " + str(type(value)))
|
||||
return "%s:%s" % (key, self.generateNode(value))
|
||||
return "%s:%s" % (self.sigmaconfig.get_fieldmapping(key), self.generateNode(value))
|
||||
|
||||
def generateValueNode(self, node):
|
||||
return "\"%s\"" % (self.cleanValue(str(node)))
|
||||
@ -140,19 +145,53 @@ class SplunkBackend(BaseBackend):
|
||||
def generateMapItemNode(self, node):
|
||||
key, value = node
|
||||
if type(value) in (str, int):
|
||||
return '%s=%s' % (key, self.generateNode(value))
|
||||
return '%s=%s' % (self.sigmaconfig.get_fieldmapping(key), self.generateNode(value))
|
||||
elif type(value) == list:
|
||||
return "(" + (" OR ".join(['%s=%s' % (key, self.generateValueNode(item)) for item in value])) + ")"
|
||||
return "(" + (" OR ".join(['%s=%s' % (self.sigmaconfig.get_fieldmapping(key), self.generateValueNode(item)) for item in value])) + ")"
|
||||
else:
|
||||
raise TypeError("Map values must be strings, numbers or lists, not " + str(type(value)))
|
||||
|
||||
def generateValueNode(self, node):
|
||||
return "\"%s\"" % (self.cleanValue(str(node)))
|
||||
|
||||
class NullBackend(BaseBackend):
|
||||
"""Does nothing, for debugging purposes."""
|
||||
identifier = "null"
|
||||
active = False
|
||||
class FieldnameListBackend(BaseBackend):
|
||||
"""List all fieldnames from given Sigma rules for creation of a field mapping configuration."""
|
||||
identifier = "fieldlist"
|
||||
active = True
|
||||
|
||||
def generate(self, parsed):
|
||||
pass
|
||||
return "\n".join(sorted(set(list(flatten(self.generateNode(parsed.getParseTree()))))))
|
||||
|
||||
def generateANDNode(self, node):
|
||||
return [self.generateNode(val) for val in node]
|
||||
|
||||
def generateORNode(self, node):
|
||||
return self.generateANDNode(node)
|
||||
|
||||
def generateNOTNode(self, node):
|
||||
return self.generateNode(node.item)
|
||||
|
||||
def generateSubexpressionNode(self, node):
|
||||
return self.generateNode(node.items)
|
||||
|
||||
def generateListNode(self, node):
|
||||
if not set([type(value) for value in node]).issubset({str, int}):
|
||||
raise TypeError("List values must be strings or numbers")
|
||||
return [self.generateNode(value) for value in node]
|
||||
|
||||
def generateMapItemNode(self, node):
|
||||
key, value = node
|
||||
if type(value) not in (str, int, list):
|
||||
raise TypeError("Map values must be strings, numbers or lists, not " + str(type(value)))
|
||||
return [self.sigmaconfig.get_fieldmapping(key)]
|
||||
|
||||
def generateValueNode(self, node):
|
||||
return []
|
||||
|
||||
# Helpers
|
||||
def flatten(l):
|
||||
for i in l:
|
||||
if type(i) == list:
|
||||
yield from flatten(i)
|
||||
else:
|
||||
yield i
|
||||
|
@ -192,7 +192,7 @@ class SigmaConditionTokenizer:
|
||||
|
||||
def index(self, item):
|
||||
return self.tokens.index(item)
|
||||
|
||||
|
||||
class SigmaParseError(Exception):
|
||||
pass
|
||||
|
||||
@ -349,3 +349,52 @@ class SigmaConditionParser:
|
||||
|
||||
def getParseTree(self):
|
||||
return(self.parsedSearch[0])
|
||||
|
||||
# Configuration
|
||||
class SigmaConfiguration:
|
||||
"""Sigma converter configuration. Contains field mappings and logsource descriptions"""
|
||||
def __init__(self, configyaml=None):
|
||||
if configyaml == None:
|
||||
self.fieldmappings = dict()
|
||||
self.logsources = dict()
|
||||
else:
|
||||
config = yaml.safe_load(configyaml)
|
||||
|
||||
try:
|
||||
self.fieldmappings = config['fieldmappings']
|
||||
except KeyError:
|
||||
self.fieldmappings = dict()
|
||||
if type(self.fieldmappings) != dict:
|
||||
raise SigmaConfigParseError("Fieldmappings must be a map")
|
||||
|
||||
try:
|
||||
self.logsources = config['logsources']
|
||||
except KeyError:
|
||||
self.logsources = dict()
|
||||
|
||||
if type(self.logsources) != dict:
|
||||
raise SigmaConfigParseError("Logsources must be a map")
|
||||
for name, logsource in self.logsources.items():
|
||||
if type(logsource) != dict:
|
||||
raise SigmaConfigParseError("Logsource definitions must be maps")
|
||||
if 'category' in logsource and type(logsource['category']) != str \
|
||||
or 'product' in logsource and type(logsource['product']) != str \
|
||||
or 'service' in logsource and type(logsource['service']) != str:
|
||||
raise SigmaConfigParseError("Logsource category, product or service must be a string")
|
||||
if 'index' in logsource:
|
||||
if type(logsource['index']) not in (str, list):
|
||||
raise SigmaConfigParseError("Logsource index must be string or list of strings")
|
||||
if type(logsource['index']) == list and not set([type(index) for index in logsource['index']]).issubset({str}):
|
||||
raise SigmaConfigParseError("Logsource index patterns must be strings")
|
||||
if 'conditions' in logsource and type(logsource['conditions']) != dict:
|
||||
raise SigmaConfigParseError("Logsource conditions must be a map")
|
||||
|
||||
def get_fieldmapping(self, fieldname):
|
||||
"""Return mapped fieldname if mapping defined or field name given in parameter value"""
|
||||
try:
|
||||
return self.fieldmappings[fieldname]
|
||||
except KeyError:
|
||||
return fieldname
|
||||
|
||||
class SigmaConfigParseError(Exception):
|
||||
pass
|
||||
|
@ -5,7 +5,9 @@ import sys
|
||||
import argparse
|
||||
import yaml
|
||||
import json
|
||||
from sigma import SigmaParser, SigmaParseError
|
||||
import pathlib
|
||||
import itertools
|
||||
from sigma import SigmaParser, SigmaParseError, SigmaConfiguration, SigmaConfigParseError
|
||||
import backends
|
||||
|
||||
def print_verbose(*args, **kwargs):
|
||||
@ -16,12 +18,25 @@ def print_debug(*args, **kwargs):
|
||||
if cmdargs.debug:
|
||||
print(*args, **kwargs)
|
||||
|
||||
def alliter(path):
|
||||
for sub in path.iterdir():
|
||||
if sub.is_dir():
|
||||
yield from alliter(sub)
|
||||
else:
|
||||
yield sub
|
||||
|
||||
def get_inputs(paths, recursive):
|
||||
if recursive:
|
||||
return list(itertools.chain.from_iterable([list(alliter(pathlib.Path(p))) for p in paths]))
|
||||
else:
|
||||
return [pathlib.Path(p) for p in paths]
|
||||
|
||||
argparser = argparse.ArgumentParser(description="Convert Sigma rules into SIEM signatures.")
|
||||
argparser.add_argument("--recurse", "-r", help="Recurse into subdirectories")
|
||||
argparser.add_argument("--recurse", "-r", action="store_true", help="Recurse into subdirectories (not yet implemented)")
|
||||
argparser.add_argument("--target", "-t", default="es-qs", choices=backends.getBackendDict().keys(), help="Output target format")
|
||||
argparser.add_argument("--target-list", "-l", action="store_true", help="List available output target formats")
|
||||
argparser.add_argument("--config", "-c", help="Configuration with field name and index mapping for target environment")
|
||||
argparser.add_argument("--output", "-o", help="Output file or filename prefix if multiple files are generated")
|
||||
argparser.add_argument("--config", "-c", help="Configuration with field name and index mapping for target environment (not yet implemented)")
|
||||
argparser.add_argument("--output", "-o", help="Output file or filename prefix if multiple files are generated (not yet implemented)")
|
||||
argparser.add_argument("--verbose", "-v", action="store_true", help="Be verbose")
|
||||
argparser.add_argument("--debug", "-d", action="store_true", help="Debugging output")
|
||||
argparser.add_argument("inputs", nargs="*", help="Sigma input files")
|
||||
@ -32,16 +47,33 @@ if cmdargs.target_list:
|
||||
print("%10s: %s" % (backend.identifier, backend.__doc__))
|
||||
sys.exit(0)
|
||||
|
||||
if cmdargs.output:
|
||||
print("--output/-o not yet implemented", file=sys.stderr)
|
||||
sys.exit(99)
|
||||
|
||||
sigmaconfig = SigmaConfiguration()
|
||||
if cmdargs.config:
|
||||
try:
|
||||
conffile = cmdargs.config
|
||||
f = open(conffile)
|
||||
sigmaconfig = SigmaConfiguration(f)
|
||||
except OSError as e:
|
||||
print("Failed to open Sigma configuration file %s: %s" % (conffile, str(e)), file=sys.stderr)
|
||||
except yaml.parser.ParserError as e:
|
||||
print("Sigma configuration file %s is no valid YAML: %s" % (conffile, str(e)), file=sys.stderr)
|
||||
except SigmaParseError as e:
|
||||
print("Sigma configuration parse error in %s: %s" % (conffile, str(e)), file=sys.stderr)
|
||||
|
||||
try:
|
||||
backend = backends.getBackend(cmdargs.target)()
|
||||
backend = backends.getBackend(cmdargs.target)(sigmaconfig)
|
||||
except LookupError as e:
|
||||
print("Backend not found!")
|
||||
print("Backend not found!", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
for sigmafile in cmdargs.inputs:
|
||||
for sigmafile in get_inputs(cmdargs.inputs, cmdargs.recurse):
|
||||
print_verbose("* Processing Sigma input %s" % (sigmafile))
|
||||
try:
|
||||
f = open(sigmafile)
|
||||
f = sigmafile.open()
|
||||
parser = SigmaParser(f)
|
||||
print_debug("Parsed YAML:\n", json.dumps(parser.parsedyaml, indent=2))
|
||||
parser.parse_sigma()
|
||||
@ -51,14 +83,14 @@ for sigmafile in cmdargs.inputs:
|
||||
print_debug("Condition Parse Tree:", condparsed)
|
||||
print(backend.generate(condparsed))
|
||||
except OSError as e:
|
||||
print("Failed to open Sigma file %s: %s" % (sigmafile, str(e)))
|
||||
print("Failed to open Sigma file %s: %s" % (sigmafile, str(e)), file=sys.stderr)
|
||||
except yaml.parser.ParserError as e:
|
||||
print("Sigma file %s is no valid YAML: %s" % (sigmafile, str(e)))
|
||||
print("Sigma file %s is no valid YAML: %s" % (sigmafile, str(e)), file=sys.stderr)
|
||||
except SigmaParseError as e:
|
||||
print("Sigma parse error in %s: %s" % (sigmafile, str(e)))
|
||||
print("Sigma parse error in %s: %s" % (sigmafile, str(e)), file=sys.stderr)
|
||||
except NotImplementedError as e:
|
||||
print("An unsupported feature is required for this Sigma rule: " + str(e))
|
||||
print("Feel free to contribute for fun and fame, this is open source :) -> https://github.com/Neo23x0/sigma")
|
||||
print("An unsupported feature is required for this Sigma rule: " + str(e), file=sys.stderr)
|
||||
print("Feel free to contribute for fun and fame, this is open source :) -> https://github.com/Neo23x0/sigma", file=sys.stderr)
|
||||
finally:
|
||||
f.close()
|
||||
print_debug()
|
||||
|
Loading…
Reference in New Issue
Block a user