Merge remote-tracking branch 'Neo23x0/master'

This commit is contained in:
Michael Haag 2017-03-08 22:51:03 -08:00
commit 923f298015
28 changed files with 488 additions and 43 deletions

1
_config.yml Normal file
View File

@ -0,0 +1 @@
theme: jekyll-theme-hacker

View 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

View File

@ -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

View File

@ -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

View 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

View 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

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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'

View 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

View File

@ -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

View 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

View 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

View 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

View 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

View 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

View File

@ -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

View File

@ -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/

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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()