Compare commits

..

99 Commits

Author SHA1 Message Date
Thomas Patzke f60e7e125f Sigma tools release 0.4
* Various bug fixes in quoting of specific characters
* New backend es-dsl
2018-05-01 00:50:07 +02:00
Thomas Patzke 7647587a8b Fixed quoting of backslashes in generated queries 2018-05-01 00:45:59 +02:00
Thomas Patzke de2ed08695 Merge branch 'ci-es' 2018-05-01 00:34:11 +02:00
Thomas Patzke a1c32123f1 Setup ES 6.2.4 in Travis CI 2018-05-01 00:23:48 +02:00
Thomas Patzke e411039b56 Fixed escaping of \u in Elasticsearch Query String queries 2018-05-01 00:05:16 +02:00
Florian Roth ae6df590a9 Delphi downloader https://goo.gl/rMVUSM 2018-04-24 23:23:21 +02:00
Florian Roth 49877a6ed0 Moved and renamed rule 2018-04-18 16:53:11 +02:00
Florian Roth 3c1c9d2b31 Merge pull request #81 from yt0ng/sigma-yt0ng
added SquiblyTwo Detection
2018-04-18 16:39:37 +02:00
Florian Roth 8420d3174a Reordered 2018-04-18 16:34:16 +02:00
yt0ng c637c2e590 Adding Detections for renamed wmic and format
https://subt0x11.blogspot.ch/2018/04/wmicexe-whitelisting-bypass-hacking.html
https://twitter.com/mattifestation/status/986280382042595328
2018-04-18 15:02:52 +02:00
Florian Roth 9b8df865b1 Extended rule 2018-04-18 12:13:45 +02:00
yt0ng a4fb39a336 also for http 2018-04-18 08:19:47 +02:00
yt0ng 169a4404c2 added SquiblyTwo Detection 2018-04-17 21:33:26 +02:00
Florian Roth 6d293d498d Merge pull request #80 from marvi/marvi-patch-1
"author" should be a string and not a list.
2018-04-17 08:27:29 +02:00
Markus Härnvi cf237cf658 "author" should be a string and not a list, according to the specification 2018-04-16 23:42:51 +02:00
Florian Roth d8bbf26f2c Added msiexec to rule in order to cover new threats
https://twitter.com/DissectMalware/status/984252467474026497
2018-04-12 09:12:50 +02:00
Thomas Patzke 15a6c5efb5 Detailed error messages for failed queries 2018-04-12 00:20:54 +02:00
Thomas Patzke aeda30a389 Python rewrite of es-qs query test 2018-04-11 23:59:44 +02:00
Florian Roth 58517907ad Improved rule to provide support for for old sysmon \REGISTRY syntax 2018-04-11 20:15:17 +02:00
Florian Roth 0ffd226293 Moved new rule to sysmon folder 2018-04-11 20:11:54 +02:00
Florian Roth 52d405bb1b Improved shell spawning rule 2018-04-11 20:09:42 +02:00
Florian Roth ef7fb4cff1 Merge pull request #78 from Karneades/patch-1
Add rule for Windows registry persistence mechanisms
2018-04-11 19:35:55 +02:00
Florian Roth b065c2c35c Simplified rule 2018-04-11 19:03:35 +02:00
Karneades fa6677a41d Remove @ in author
Be nice to Travis: "error    syntax error: found character '@' that cannot start any token"
2018-04-11 15:21:42 +02:00
Karneades be3c27981f Add rule for Windows registry persistence mechanisms 2018-04-11 15:13:00 +02:00
Thomas Patzke 788111f174 Fixes for Elasticsearch query correctness CI tests
* Quoting in rule
* Reading queries without special processing of backslashes

Unfortunately, backslashes still cause breaks caused by Bash handling of
them.
2018-04-09 22:33:29 +02:00
Florian Roth 56172ae174 Corrected CrackMapExec rule 2018-04-09 08:40:03 +02:00
Florian Roth a9c7fe202e Rule: Windows shell spawning suspicious program 2018-04-09 08:37:30 +02:00
Florian Roth 8ddd40e18e PowerShell Cradle - WebDAV UA 2018-04-09 08:37:30 +02:00
Florian Roth e53826e167 Extended Sysmon Office Shell rule 2018-04-09 08:37:30 +02:00
Florian Roth 6eb8cdfeab TSCookie UA 2018-04-09 08:37:30 +02:00
Thomas Patzke 05928d4f8f Merge pull request #76 from HacknowledgeCH/es-dsl
es-dsl backend
2018-04-08 23:39:23 +02:00
Thomas Patzke f113832c04 Merge pull request #69 from jmallette/rules
Create cmdkey recon rule
2018-04-08 23:23:30 +02:00
Thomas Patzke 35d43c5ed9 Merge pull request #77 from yt0ng/sigma-yt0ng
added NCSC CrackMapExecWin Description in apt_dragonfly.yml
2018-04-08 23:21:49 +02:00
root 69671733a8 added NCSC CrackMapExecWin Description in apt_dragonfly.yml 2018-04-08 17:10:00 +02:00
milkmix 0b3b0c3aaf imported es-dsl code from repo 2018-04-06 17:36:11 +02:00
Thomas Patzke 24d94d39b8 CI: Testing backend es-qs against Elasticsearch 2018-04-04 00:32:48 +02:00
Thomas Patzke 4183b1b59e Sigma tools release 0.3.3 2018-03-29 11:17:03 +02:00
Thomas Patzke 22ee6f4521 sigmac: escaped wildcards (\* and \?) are passed in generated query 2018-03-29 11:15:20 +02:00
Thomas Patzke 17c1c1adff Added field name mappings to HELK configuration 2018-03-27 14:41:02 +02:00
Thomas Patzke a3e02ea70f Various rule fixes
* Field name: LogonProcess -> LogonProcessName
* Field name: Message -> AuditPolicyChanges
* Field name: ProcessCommandLine -> CommandLine
* Removed Type match in Kerberos RC4 encryption rule
  Problematic because text representation not unified and audit failures are possibly interesting events
* Removed field 'Severity' from rules (Redundant)
* Rule decomposition of win_susp_failed_logons_single_source) because of different field names
* Field name: SubjectAccountName -> SubjectUserName
* Field name: TargetProcess -> TargetImage
* Field name: TicketEncryption -> TicketEncryptionType
* Field name: TargetFileName -> TargetFilename
2018-03-27 14:35:49 +02:00
Thomas Patzke b1bfa64231 Removed redundant 'EventLog' conditions 2018-03-26 00:36:40 +02:00
Thomas Patzke f68af2a5da Added reference to Kerberos RC4 rule 2018-03-25 23:19:01 +02:00
Thomas Patzke dacc6ae3d3 Fieldname case: Commandline -> CommandLine 2018-03-25 23:08:28 +02:00
Florian Roth e141a834ff Rule: Ping hex IP address
https://github.com/vysec/Aggressor-VYSEC/blob/master/ping.cna
2018-03-23 17:00:00 +01:00
Florian Roth c10da5b734 Improved Chafer activity rule 2018-03-23 10:50:40 +01:00
Florian Roth a797a281ac Rule: Chafer / OilRig activity Mar 18
https://nyotron.com/nyotron-discovers-next-generation-oilrig-attacks/
2018-03-23 08:59:16 +01:00
Thomas Patzke 3962520848 Merge branch 'devel-sigmac' 2018-03-22 00:05:51 +01:00
Thomas Patzke 5f8b60cc24 sigmac: Improved fieldlist backend
* Unique list of fields for multiple rules
* Aggregation support
2018-03-22 00:03:51 +01:00
Florian Roth f220e61adc Fixed second selection in rule 2018-03-21 10:47:14 +01:00
Florian Roth 70c2f973a3 Rule: Smbexec.py Service Installation 2018-03-21 10:44:37 +01:00
Florian Roth 3c968d4ec6 Fixed rule for any ControlSets 2018-03-21 10:44:37 +01:00
Thomas Patzke 5c0f811f4a Sigma tools release 0.3.2 2018-03-21 01:15:19 +01:00
Thomas Patzke 0018503501 sigmac: Fixed rulecommend backend option 2018-03-21 01:13:10 +01:00
Thomas Patzke 7360a68741 Sigma tools release 0.3.1 2018-03-21 00:59:23 +01:00
Thomas Patzke 4a9849b161 sigmac: improved backend options
* parsing in main class
* help
2018-03-21 00:53:44 +01:00
Thomas Patzke bd20ffdad9 sigmac/kibana: curl URL quoted 2018-03-21 00:22:00 +01:00
Thomas Patzke 177e2acf8e Updated README 2018-03-20 23:54:00 +01:00
Florian Roth 97204d8dc0 Renamed rule 2018-03-20 15:04:11 +01:00
Florian Roth e9fcfcba7f Improved NetNTLM downgrade rule 2018-03-20 15:03:55 +01:00
Florian Roth a7eb4d3e34 Renamed rule 2018-03-20 11:12:35 +01:00
Florian Roth b84bbd327b Rule: NetNTLM Downgrade Attack
https://www.optiv.com/blog/post-exploitation-using-netntlm-downgrade-attacks
2018-03-20 11:07:21 +01:00
Florian Roth a6d293e31d Improved tscon rule 2018-03-20 10:54:04 +01:00
Florian Roth 8fb6bc7a8a Rule: Suspicious taskmgr as LOCAL_SYSTEM 2018-03-19 16:36:39 +01:00
Florian Roth af8be8f064 Several rule updates 2018-03-19 16:36:15 +01:00
Florian Roth 648ac5a52e Rules: tscon.exe anomalies
http://www.korznikov.com/2017/03/0-day-or-feature-privilege-escalation.html
https://medium.com/@networksecurity/rdp-hijacking-how-to-hijack-rds-and-remoteapp-sessions-transparently-to-move-through-an-da2a1e73a5f6
2018-03-17 19:14:13 +01:00
Thomas Patzke 3f5f3a8d50 sigmac: Remove problematic characters from rule identifiers 2018-03-17 00:44:50 +01:00
Thomas Patzke f6858c436a sigmac: Kibana curl output generates one index pattern line per pattern 2018-03-16 23:53:12 +01:00
Thomas Patzke 578118315c Merge branch 'devel-sigmac' into helk 2018-03-16 23:48:13 +01:00
Thomas Patzke e162ba0155 Added HELK configuration 2018-03-16 23:42:31 +01:00
Florian Roth ff45901ea3 Merge pull request #71 from Karneades/patch-1
Add missing binaries
2018-03-16 11:49:37 +01:00
Karneades 49c12f1df8 Add missing binaries 2018-03-16 10:52:43 +01:00
Florian Roth a257b7d9d7 Rule: Stickykey improved 2018-03-16 09:10:07 +01:00
Florian Roth 8b31767d31 Rule: PsExec usage 2018-03-15 19:54:22 +01:00
Florian Roth 0460e7f18a Rule: Suspicious process started from taskmgr 2018-03-15 19:54:03 +01:00
Florian Roth f5494c6f5f Rule: StickyKey-ike backdoor usage 2018-03-15 19:53:34 +01:00
Florian Roth d9d27fec74 Improved EquationGroup dll load rule 2018-03-11 01:22:04 +01:00
Thomas Patzke d8bd65f9ff sigmac: Added testcase for Kibana curl script output 2018-03-11 00:30:20 +01:00
Thomas Patzke 13ec4c3e3b sigmac: Kibana curl importer script 2018-03-11 00:25:12 +01:00
Florian Roth 74c2f91a7d Extended the Slingshot APT rule 2018-03-10 16:44:18 +01:00
Florian Roth 66d52cfeef Rule: Defrag deactivation 2018-03-10 15:49:50 +01:00
Florian Roth ef75f2a248 Minor adjustment in: EquationGroup dll_u load 2018-03-10 12:24:49 +01:00
Florian Roth e9d16bfae1 Bugfix in: EquationGroup dll_u load 2018-03-10 12:22:53 +01:00
Florian Roth 5ae5c9de19 Rule: Outlook spawning shells to detect Turla like C&C via Outlook 2018-03-10 09:04:11 +01:00
Florian Roth 6a65a7a1bf EquationGroup dll_u load 2018-03-10 09:04:11 +01:00
jmallette aff46be8a3 Create cmdkey recon rule 2018-03-08 13:25:05 -05:00
Thomas Patzke ada1ca94ea JPCERT rules
* Addition of ntdsutil.exe rule
* Added new link to existing rules
2018-03-08 00:10:19 +01:00
Thomas Patzke 8ee24bf150 WMI persistence rules derived from blog article
https://www.eideon.com/2018-03-02-THL03-WMIBackdoors/#so-to-summarize
2018-03-07 23:05:10 +01:00
Thomas Patzke 1dc3ae1a8e Fixed merge_sigma failing test 2018-03-07 00:20:35 +01:00
Thomas Patzke 54d9e52527 Sigma tools release 0.3 2018-03-06 23:21:13 +01:00
Thomas Patzke 3b8b04fe09 Merge branch 'devel-sigmac' 2018-03-06 23:19:45 +01:00
Thomas Patzke 8041f77abd Merged similar rules 2018-03-06 23:19:11 +01:00
Thomas Patzke 84645f4e59 Simplified rule conditions with new condition constructs 2018-03-06 23:14:43 +01:00
Thomas Patzke 7141729ffc sigma/parser: Introduced new conditions
* Any definition: 1 of them
* All definitions: all of them
* Any of selected definitions: 1 of def* (wildcard)
* All of selected definitions: all of def* (wildcard)
2018-03-06 23:13:42 +01:00
Florian Roth b9102d0b0a Improved sigma2elastalert 2018-03-05 12:05:47 +01:00
Florian Roth 1ecfd83a6a Missing separator 2018-03-05 11:30:01 +01:00
Thomas Patzke 6b69f423da Merging sigma2elastalert 2018-03-04 23:27:23 +01:00
Thomas Patzke 17e8f06161 Added notice regarding contributed tools 2018-03-04 23:26:38 +01:00
David ROUTIN 00177560ca Added sigma2elastalert.py 2018-03-04 23:26:06 +01:00
80 changed files with 1496 additions and 165 deletions
+5 -1
View File
@@ -3,9 +3,13 @@ python:
- 3.5
- 3.6
- pypy3
services:
- elasticsearch
cache: pip
before_install:
- curl -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.2.4.deb && sudo dpkg -i --force-confnew elasticsearch-6.2.4.deb && sudo service elasticsearch restart
install:
- pip install -r tools/requirements-devel.txt
script:
- make test
- make test-backend-es-qs
+7 -1
View File
@@ -21,6 +21,7 @@ test-sigmac:
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t xpack-watcher rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t splunk rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t logpoint rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t es-dsl rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t splunk -f 'level>=high,level<=critical,status=stable,logsource=windows' rules/ > /dev/null
! coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t splunk -f 'level>=high,level<=critical,status=xstable,logsource=windows' rules/ > /dev/null
! coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t splunk -f 'level>=high,level<=xcritical,status=stable,logsource=windows' rules/ > /dev/null
@@ -30,7 +31,9 @@ test-sigmac:
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -c tools/config/elk-windows.yml -t es-qs rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -c tools/config/elk-linux.yml -t es-qs rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -c tools/config/elk-windows.yml -t kibana rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -c tools/config/elk-windows.yml -Ooutput=curl -t kibana rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -c tools/config/elk-linux.yml -t kibana rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -c tools/config/elk-linux.yml -Ooutput=curl -t kibana rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -c tools/config/elk-windows.yml -t xpack-watcher rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -c tools/config/elk-linux.yml -t xpack-watcher rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -c tools/config/elk-defaultindex.yml -t xpack-watcher rules/ > /dev/null
@@ -57,7 +60,10 @@ test-sigmac:
test-merge:
tests/test-merge.sh
! coverage run -a --include=$(COVSCOPE) tools/merge_sigma.py tests/not_existing.yml > /dev/null
! coverage run -a --include=$(COVSCOPE) tools/merge_sigma tests/not_existing.yml > /dev/null
test-backend-es-qs:
tests/test-backend-es-qs.py
build: tools/sigmac tools/merge_sigma tools/sigma/*.py tools/setup.py tools/setup.cfg
cd tools && python3 setup.py bdist_wheel
+29 -18
View File
@@ -18,6 +18,8 @@ This repository contains:
* Open repository for sigma signatures in the `./rules`subfolder
* A converter that generate searches/queries for different SIEM systems [work in progress]
![sigma_description](./images/Sigma-description.png)
## Hack.lu 2017 Talk
[![Sigma - Generic Signatures for Log Events](https://preview.ibb.co/cMCigR/Screen_Shot_2017_10_18_at_15_47_15.png)](https://www.youtube.com/watch?v=OheVuE9Ifhs "Sigma - Generic Signatures for Log Events")
@@ -32,22 +34,6 @@ This repository contains:
* Write a rule converter for your custom log analysis tool and process new Sigma rules automatically
* Provide a free or commercial feed for Sigma signatures
# Sigma Converter
The converter is currently under development in the *devel-sigmac* branch of this project. It has currently the
following capabilities:
* Parsing of Sigma rule files
* Conversion of searches into Elasticsearch and Splunk queries
Planned main features are:
* Conversion of aggregation expressions (after the pipe character)
* Output of Kibana JSON configurations
Support for further SIEM solutions can be added by developing an corresponsing output backend class.
![sigma_description](./images/Sigma-description.png)
# Why Sigma
@@ -94,7 +80,7 @@ Sysmon: Web Shell Detection
Windows 'Security' Eventlog: Suspicious Number of Failed Logons from a Single Source Workstation
![sigma_rule example5](./images/Sigma_rule_example5.png)
## Sigma Toolchain
## Sigma Tools
Sigmac converts sigma rules into queries or inputs of the supported targets listed below. It acts as a frontend to the
Sigma library that may be used to integrate Sigma support in other projects. Further, there's `merge_sigma.py` which
@@ -105,9 +91,13 @@ merges multiple YAML documents of a Sigma rule collection into simple Sigma rule
### Supported Targets
* [Splunk](https://www.splunk.com/)
* [ElasticSearch](https://www.elastic.co/)
* [Elasticsearch](https://www.elastic.co/)
* [Kibana](https://www.elastic.co/de/products/kibana)
* [Elastic X-Pack Watcher](https://www.elastic.co/guide/en/x-pack/current/xpack-alerting.html)
* [Logpoint](https://www.logpoint.com)
* Grep with Perl-compatible regular expression support
New targets are continuously developed. A current list can be obtained with `sigmac --target-list` or `sigmac -l`.
### Requirements
@@ -121,6 +111,27 @@ It's available on PyPI. Install with:
pip3 install sigmatools
```
Alternatively, if used from the Sigma Github repository, the Python dependencies can be installed with:
```bash
pip3 install -r tools/requirements.txt
```
For development (e.g. execution of integration tests with `make` and packaging), further dependencies are required and can be installed with:
```bash
pip3 install -r tools/requirements-devel.txt
```
## Contributed Scripts
The directory `contrib` contains scripts that were contributed by the community:
* `sigma2elastalert.py`i by David Routin: A script that converts Sigma rules to Elastalert configurations. This tool
uses *sigmac* and expects it in its path.
These tools are not part of the main toolchain and maintained separately by their authors.
# Next Steps
* Integration of feedback into the rule specifications
+173
View File
@@ -0,0 +1,173 @@
#!/usr/bin/python
# Copyright 2018 David Routin
# 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/>.
"""
Project: sigma2elastalert.py
Date: 25 Feb 2018
Author: David ROUTIN (@Rewt_1)
Version: 1.0
Description: This script creates elastalert configuration files from Sigma SIEM rules.
"""
import re
import os
import glob
import subprocess
import argparse
import yaml
import traceback
parser = argparse.ArgumentParser()
parser.add_argument("--eshost", help="Elasticsearch host", type=str, required=True)
parser.add_argument("--esport", help="Elasticsearch port", type=str, required=True)
parser.add_argument("--ruledir", help="sigma rule directory path to convert", type=str, required=True)
parser.add_argument("--index", help="Elasticsearch index name egs: \"winlogbeat-*\"", type=str, required=True)
parser.add_argument("--email", help="email address to send mail alert", type=str, required=True)
parser.add_argument("--outdir", help="output directory to create elastalert rules", type=str, required=True)
parser.add_argument("--sigmac", help="Sigmac location", default="../tools/sigmac", type=str)
parser.add_argument("--realerttime", help="Realert time (optional value, default 5 minutes)", type=str, default=5)
parser.add_argument("--debug", help="Show debug output", type=bool, default=False)
args = parser.parse_args()
custom_query_keys = ["sensor", "Hostname", "EventID", "src_ip", "dst_ip"]
template="""es_host: ESHOST
es_port: ESPORT
name: "TITLE"
description: "DESCRIPTION"
index: INDEX
filter:
- query:
query_string:
query: 'QUERY'
realert:
minutes: MINUTES
query_key: UNIQKEYS
type: any
include: UNIQKEYS
alert:
- "email"
# (required, email specific)
# a list of email addresses to send alerts to
email:
- "EMAIL"
"""
def return_json_obj(x,custom_query_keys):
"""
Function used to filter all ES query object as unique value including predefined list from custom_query_keys
:param x: must contains ES query output
:param custom_query_keys: takes the list of predefined element to match in document
:return: a clean list (set) of all the query keys (EventID,TargetUserName...)
"""
# type: (str, list) -> list
y = x.replace(" ", "\n").split()
out = set()
for i in y:
out.update(re.findall("([a-zA-Z]+)\:", i))
for qk in custom_query_keys:
try:
out.remove(qk)
except:
pass
out = list(out)
count = 0
for qk in custom_query_keys:
count += 1
out.insert(count-1, qk)
return out
def rule_element(file_content, elements):
"""
Function used to get specific element from yaml document and return content
:type file_content: str
:type elements: list
:param file_content:
:param elements: list of elements of the yaml document to get "title", "description"
:return: the value of the key in the yaml document
"""
try:
yaml.load(file_content.replace("---",""))
except:
raise Exception('Unsupported')
element_output = ""
for e in elements:
try:
element_output = yaml.load(file_content.replace("---",""))[e]
except:
pass
if element_output is None:
return ""
return element_output
def get_rule_as_esqs(file):
"""
Function used to get Elastic query output from rule fome
:type file: str
:param file: rule filename
:return: string es query
"""
if not os.path.exists(args.sigmac):
print("Cannot find sigmac rule coverter at '%s', please set a correct location via '--sigmac'")
cmd = [args.sigmac, file, "--target", "es-qs"]
output = subprocess.Popen(cmd,stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.read()
if "unsupported" in output:
raise Exception('Unsupported output at this time')
output = output.split("\n")
# Remove empty string from \n
output = [a for a in output if a]
# Handle case of multiple queries returned
if len(output) > 1:
return " OR ".join(output)
return "".join(output)
# Dictionary that contains args set at launch time
convert_args = {
"ESHOST": args.eshost,
"ESPORT": args.esport,
"INDEX": args.index,
"EMAIL": args.email,
"MINUTES": args.realerttime
}
for file in glob.glob(args.ruledir + "/*"):
output_elast_config = template
try:
print("Processing %s ..." % file)
with open(file, "rb") as f:
file_content = f.read()
# Dictionary that contains args with values returned by functions
translate_func = {'QUERY': get_rule_as_esqs(file),
'TITLE': rule_element(file_content, ["title", "name"]),
'DESCRIPTION': rule_element(file_content, ["description"]),
'UNIQKEYS': str(return_json_obj(get_rule_as_esqs(file), custom_query_keys))
}
for entry in convert_args:
output_elast_config = re.sub(entry, str(convert_args[entry]), output_elast_config)
for entry in translate_func:
output_elast_config = re.sub(entry, translate_func[entry], output_elast_config)
print "Converting file " + file
with open(os.path.join(args.outdir, "sigma-" + file.split("/")[-1]), "w") as f:
f.write(output_elast_config)
except Exception as e:
if args.debug:
traceback.print_exc()
print "error " + str(file) + "----" + str(e)
pass
Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 43 KiB

@@ -16,7 +16,7 @@ detection:
# SQL Server
- Unclosed quotation mark
# SQLite
- near "*": syntax error
- 'near "*": syntax error'
- SELECTs to the left and right of UNION do not have the same number of result columns
condition: keywords
falsepositives:
+1
View File
@@ -1,3 +1,4 @@
---
action: global
title: APT29 Google Update Service Install
description: 'This method detects malicious services mentioned in APT29 report by FireEye. The legitimate path for the Google update service is C:\Program Files (x86)\Google\Update\GoogleUpdate.exe so the service names and executable locations used by APT29 are specific enough to be detected in log files.'
+53
View File
@@ -0,0 +1,53 @@
---
action: global
title: Chafer Activity
description: Detects Chafer activity attributed to OilRig as reported in Nyotron report in March 2018
references:
- https://nyotron.com/nyotron-discovers-next-generation-oilrig-attacks/
date: 2018/03/23
author: Florian Roth, Markus Neis
detection:
condition: 1 of them
falsepositives:
- Unknown
level: critical
---
logsource:
product: windows
service: system
detection:
selection_service:
EventID: 7045
ServiceName:
- 'SC Scheduled Scan'
- 'UpdatMachine'
---
logsource:
product: windows
service: sysmon
detection:
selection_reg1:
EventID: 13
TargetObject:
- '*SOFTWARE\Microsoft\Windows\CurrentVersion\UMe'
- '*SOFTWARE\Microsoft\Windows\CurrentVersion\UT'
EventType: 'SetValue'
selection_reg2:
EventID: 13
TargetObject: '*\Control\SecurityProviders\WDigest\UseLogonCredential'
EventType: 'SetValue'
Details: 'DWORD (0x00000001)'
selection_process1:
EventID: 1
CommandLine:
- '*\Service.exe i'
- '*\Service.exe u'
- '*\microsoft\Taskbar\autoit3.exe'
- 'C:\wsc.exe*'
selection_process2:
EventID: 1
Image: '*\Windows\Temp\DB\*.exe'
selection_process3:
EventID: 1
CommandLine: '*\nslookup.exe -q=TXT*'
ParentImage: '*\Autoit*'
+36
View File
@@ -0,0 +1,36 @@
---
action: global
title: CrackMapExecWin
description: Detects CrackMapExecWin Activity as Described by NCSC
status: experimental
references:
- https://www.ncsc.gov.uk/alerts/hostile-state-actors-compromising-uk-organisations-focus-engineering-and-industrial-control
author: Markus Neis
detection:
condition: 1 of them
falsepositives:
- None
level: critical
---
# Windows Audit Log
logsource:
product: windows
service: security
description: 'Requirements: Audit Policy : Detailed Tracking > Audit Process creation, Group Policy : Administrative Templates\System\Audit Process Creation'
detection:
selection1:
# Does not require group policy 'Audit Process Creation' > Include command line in process creation events
EventID: 4688
NewProcessName:
- '*\crackmapexec.exe'
---
# Sysmon
logsource:
product: windows
service: sysmon
detection:
selection1:
# Does not require group policy 'Audit Process Creation' > Include command line in process creation events
EventID: 1
Image:
- '*\crackmapexec.exe'
+1 -1
View File
@@ -16,7 +16,7 @@ detection:
selection2:
EventID: 1
CommandLine: '*\AppData\Roaming\MICROS~1\Windows\Caches\NavShExt.dll,Setting'
condition: selection1 or selection2
condition: 1 of them
falsepositives:
- Unknown
level: critical
+1 -1
View File
@@ -15,7 +15,7 @@ detection:
src:
- '69.42.98.86'
- '89.185.234.145'
condition: outgoing or incoming
condition: 1 of them
falsepositives:
- Unknown
level: high
@@ -0,0 +1,39 @@
---
action: global
title: Equation Group DLL_U Load
description: Detects a specific tool and export used by EquationGroup
references:
- https://github.com/adamcaudill/EquationGroupLeak/search?utf8=%E2%9C%93&q=dll_u&type=
- https://securelist.com/apt-slingshot/84312/
- https://twitter.com/cyb3rops/status/972186477512839170
author: Florian Roth
date: 2018/03/10
detection:
selection1:
Image: '*\rundll32.exe'
CommandLine: '*,dll_u'
selection2:
CommandLine: '* -export dll_u *'
condition: 1 of them
falsepositives:
- Unknown
level: critical
---
logsource:
product: windows
service: sysmon
detection:
selection1:
EventID: 1
selection2:
EventID: 1
---
logsource:
product: windows
service: security
description: 'Requirements: Audit Policy : Detailed Tracking > Audit Process creation, Group Policy : Administrative Templates\System\Audit Process Creation'
detection:
selection1:
EventID: 4688
selection2:
EventID: 4688
+1 -1
View File
@@ -18,7 +18,7 @@ detection:
selection2:
EventID: 1
Command: 'loaddll -a *'
condition: selection1 or selection2
condition: 1 of them
fields:
- EventID
- CommandLine
+35
View File
@@ -0,0 +1,35 @@
---
action: global
title: Defrag Deactivation
description: Detects the deactivation of the Scheduled defragmentation task as seen by Slingshot APT group
references:
- https://securelist.com/apt-slingshot/84312/
author: Florian Roth
date: 2018/03/10
logsource:
product: windows
service: security
description: 'Requirements: Audit Policy : Audit Other Object Access Events > Success'
detection:
condition: selection
falsepositives:
- Unknown
level: medium
---
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 1
CommandLine:
- '*schtasks* /delete *Defrag\ScheduledDefrag*'
---
logsource:
product: windows
service: security
description: 'Requirements: Audit Policy : Audit Other Object Access Events > Success'
detection:
selection:
EventID: 4701
TaskName: '\Microsoft\Windows\Defrag\ScheduledDefrag'
@@ -0,0 +1,21 @@
title: Windows PowerShell WebDav User Agent
status: experimental
description: Detects Windows PowerShell Web Access
references:
- https://mgreen27.github.io/posts/2018/04/02/DownloadCradle.html
author: Florian Roth
date: 2018/04/06
logsource:
category: proxy
detection:
selection:
UserAgent: 'Microsoft-WebDAV-MiniRedir/*'
condition: selection
fields:
- ClientIP
- URL
- UserAgent
falsepositives:
- Administrative scripts that download files from the Internet
- Administrative scripts that retrieve certain website contents
level: high
+2
View File
@@ -28,6 +28,8 @@ detection:
- 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NETCLR 2.0.50727)' # APT17
- 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; SV1)' # Bronze Butler - Daserf
- 'Mozilla/4.0 (compatible; MSIE 11.0; Windows NT 6.1; SV1)' # Bronze Butler - Daserf
- 'Mozilla/4.0 (compatible; MSIE 8.0; Win32)' # TSCookie https://app.any.run/tasks/0996b314-5133-491b-8d23-d431ffdec597
- 'Mozilla v5.1 (Windows NT 6.1; rv:6.0.1) Gecko/20100101 Firefox/6.0.1' # Delphi downloader https://www.welivesecurity.com/2018/04/24/sednit-update-analysis-zebrocy/
condition: selection
fields:
- ClientIP
@@ -13,7 +13,6 @@ detection:
EventID: 4624
LogonType: 10
AuthenticationPackageName: Negotiate
Severity: Information
AccountName: 'Admin-*'
condition: selection
falsepositives:
@@ -11,7 +11,7 @@ detection:
EventID: 5140
ShareName: Admin$
filter:
SubjectAccountName: '*$'
SubjectUserName: '*$'
condition: selection and not filter
falsepositives:
- Legitimate administrative activity
@@ -12,7 +12,7 @@ detection:
EventID: 4707
keywords:
- 'SeEnableDelegationPrivilege'
condition: selection and keywords
condition: all of them
falsepositives:
- Unknown
level: high
@@ -20,7 +20,7 @@ detection:
EventID: 5136
ObjectClass: 'user'
AttributeLDAPDisplayName: 'servicePrincipalName'
condition: selection1 or selection2 or selection3
condition: 1 of them
falsepositives:
- Unknown
level: high
@@ -16,7 +16,7 @@ logsource:
detection:
selection:
EventID: 4719
Message: 'removed'
AuditPolicyChanges: 'removed'
condition: selection
falsepositives:
- Unknown
@@ -0,0 +1,21 @@
title: smbexec.py Service Installation
description: Detects the use of smbexec.py tool by detecting a specific service installation
author: Omer Faruk Celik
date: 2018/03/20
references:
- https://blog.ropnop.com/using-credentials-to-own-windows-boxes-part-2-psexec-and-services/
logsource:
product: windows
detection:
service_installation:
EventID: 7045
ServiceName: 'BTOBTO'
ServiceFileName: '*\execute.bat'
condition: service_installation
fields:
- ServiceName
- ServiceFileName
falsepositives:
- Penetration Test
- Unknown
level: critical
@@ -7,26 +7,26 @@ logsource:
detection:
selection:
EventID: 7045
wce:
malsvc_wce:
ServiceName:
- 'WCESERVICE'
- 'WCE SERVICE'
paexec:
malsvc_paexec:
ServiceFileName: '*\PAExec*'
winexe:
malsvc_winexe:
ServiceFileName: 'winexesvc.exe*'
pwdumpx:
malsvc_pwdumpx:
ServiceFileName: '*\DumpSvc.exe'
wannacry:
malsvc_wannacry:
ServiceName: 'mssecsvc2.0'
persistence:
malsvc_persistence:
ServiceFileName: '* net user *'
others:
malsvc_others:
ServiceName:
- 'pwdump*'
- 'gsecdump*'
- 'cachedump*'
condition: selection and ( wce or paexec or winexe or pwdumpx or wannacry or persistence or others )
condition: selection and 1 of malsvc_*
falsepositives:
- Penetration testing
level: critical
@@ -4,6 +4,7 @@ description: Detects wceaux.dll access while WCE pass-the-hash remote command ex
author: Thomas Patzke
references:
- https://www.jpcert.or.jp/english/pub/sr/ir_research.html
- https://jpcertcc.github.io/ToolAnalysisResultSheet
logsource:
product: windows
service: security
@@ -0,0 +1,40 @@
---
action: global
title: NetNTLM Downgrade Attack
description: Detects post exploitation using NetNTLM downgrade attacks
reference:
- https://www.optiv.com/blog/post-exploitation-using-netntlm-downgrade-attacks
author: Florian Roth
date: 2018/03/20
detection:
condition: 1 of them
falsepositives:
- Unknown
level: critical
---
logsource:
product: windows
service: sysmon
detection:
selection1:
EventID: 13
TargetObject:
- '*SYSTEM\*ControlSet*\Control\Lsa\lmcompatibilitylevel'
- '*SYSTEM\*ControlSet*\Control\Lsa\NtlmMinClientSec'
- '*SYSTEM\*ControlSet*\Control\Lsa\RestrictSendingNTLMTraffic'
EventType: 'SetValue'
---
# Windows Security Eventlog: Process Creation with Full Command Line
logsource:
product: windows
service: security
description: 'Requirements: Audit Policy : Object Access > Audit Registry (Success)'
detection:
selection2:
EventID: 4657
OperationType: 'Existing registry value modified'
ObjectName: '\REGISTRY\MACHINE\SYSTEM\*ControlSet*\Control\Lsa'
ObjectValueName:
- 'LmCompatibilityLevel'
- 'NtlmMinClientSec'
- 'RestrictSendingNTLMTraffic'
+2 -2
View File
@@ -12,12 +12,12 @@ detection:
selection:
- EventID: 4624
LogonType: '3'
LogonProcess: 'NtLmSsp'
LogonProcessName: 'NtLmSsp'
WorkstationName: '%Workstations%'
ComputerName: '%Workstations%'
- EventID: 4625
LogonType: '3'
LogonProcess: 'NtLmSsp'
LogonProcessName: 'NtLmSsp'
WorkstationName: '%Workstations%'
ComputerName: '%Workstations%'
filter:
@@ -14,50 +14,50 @@ detection:
# CamMute
selection_cammute:
EventID: 4688
ProcessCommandLine: '*\CamMute.exe'
CommandLine: '*\CamMute.exe'
filter_cammute:
EventID: 4688
ProcessCommandLine: '*\Lenovo\Communication Utility\*'
CommandLine: '*\Lenovo\Communication Utility\*'
# Chrome Frame Helper
selection_chrome_frame:
EventID: 4688
ProcessCommandLine: '*\chrome_frame_helper.exe'
CommandLine: '*\chrome_frame_helper.exe'
filter_chrome_frame:
EventID: 4688
ProcessCommandLine: '*\Google\Chrome\application\*'
CommandLine: '*\Google\Chrome\application\*'
# Microsoft Device Emulator
selection_devemu:
EventID: 4688
ProcessCommandLine: '*\dvcemumanager.exe'
CommandLine: '*\dvcemumanager.exe'
filter_devemu:
EventID: 4688
ProcessCommandLine: '*\Microsoft Device Emulator\*'
CommandLine: '*\Microsoft Device Emulator\*'
# Windows Media Player Gadget
selection_gadget:
EventID: 4688
ProcessCommandLine: '*\Gadget.exe'
CommandLine: '*\Gadget.exe'
filter_gadget:
EventID: 4688
ProcessCommandLine: '*\Windows Media Player\*'
CommandLine: '*\Windows Media Player\*'
# HTML Help Workshop
selection_hcc:
EventID: 4688
ProcessCommandLine: '*\hcc.exe'
CommandLine: '*\hcc.exe'
filter_hcc:
EventID: 4688
ProcessCommandLine: '*\HTML Help Workshop\*'
CommandLine: '*\HTML Help Workshop\*'
# Hotkey Command Module for Intel Graphics Contollers
selection_hkcmd:
EventID: 4688
ProcessCommandLine: '*\hkcmd.exe'
CommandLine: '*\hkcmd.exe'
filter_hkcmd:
EventID: 4688
ProcessCommandLine:
CommandLine:
- '*\System32\*'
- '*\SysNative\*'
- '*\SysWowo64\*'
@@ -65,10 +65,10 @@ detection:
# McAfee component
selection_mc:
EventID: 4688
ProcessCommandLine: '*\Mc.exe'
CommandLine: '*\Mc.exe'
filter_mc:
EventID: 4688
ProcessCommandLine:
CommandLine:
- '*\Microsoft Visual Studio*'
- '*\Microsoft SDK*'
- '*\Windows Kit*'
@@ -76,10 +76,10 @@ detection:
# MsMpEng - Microsoft Malware Protection Engine
selection_msmpeng:
EventID: 4688
ProcessCommandLine: '*\MsMpEng.exe'
CommandLine: '*\MsMpEng.exe'
filter_msmpeng:
EventID: 4688
ProcessCommandLine:
CommandLine:
- '*\Microsoft Security Client\*'
- '*\Windows Defender\*'
- '*\AntiMalware\*'
@@ -87,26 +87,26 @@ detection:
# Microsoft Security Center
selection_msseces:
EventID: 4688
ProcessCommandLine: '*\msseces.exe'
CommandLine: '*\msseces.exe'
filter_msseces:
EventID: 4688
ProcessCommandLine: '*\Microsoft Security Center\*'
CommandLine: '*\Microsoft Security Center\*'
# Microsoft Office 2003 OInfo
selection_oinfo:
EventID: 4688
ProcessCommandLine: '*\OInfoP11.exe'
CommandLine: '*\OInfoP11.exe'
filter_oinfo:
EventID: 4688
ProcessCommandLine: '*\Common Files\Microsoft Shared\*'
CommandLine: '*\Common Files\Microsoft Shared\*'
# OLE View
selection_oleview:
EventID: 4688
ProcessCommandLine: '*\OleView.exe'
CommandLine: '*\OleView.exe'
filter_oleview:
EventID: 4688
ProcessCommandLine:
CommandLine:
- '*\Microsoft Visual Studio*'
- '*\Microsoft SDK*'
- '*\Windows Kit*'
@@ -115,10 +115,10 @@ detection:
# RC
selection_rc:
EventID: 4688
ProcessCommandLine: '*\OleView.exe'
CommandLine: '*\OleView.exe'
filter_rc:
EventID: 4688
ProcessCommandLine:
CommandLine:
- '*\Microsoft Visual Studio*'
- '*\Microsoft SDK*'
- '*\Windows Kit*'
@@ -0,0 +1,16 @@
title: PsExec Service Start
description: Detects a PsExec service start
author: Florian Roth
date: 2018/03/13
logsource:
product: windows
service: security
description: 'Requirements: Audit Policy : Detailed Tracking > Audit Process creation, Group Policy : Administrative Templates\System\Audit Process Creation'
detection:
selection:
EventID: 4688
CommandLine: 'C:\Windows\PSEXESVC.exe'
condition: 1 of them
falsepositives:
- Administrative activity
level: low
@@ -12,7 +12,6 @@ logsource:
service: system
detection:
selection:
EventLog: System
EventID: 1033
condition: selection
falsepositives:
@@ -12,7 +12,6 @@ logsource:
service: system
detection:
selection:
- EventLog: System
EventID:
- 1031
- 1032
@@ -5,15 +5,20 @@ logsource:
product: windows
service: security
detection:
selection:
selection1:
EventID:
- 529
- 4625
- 4776
UserName: not null
SourceWorkstation: not null
WorkstationName: not null
selection2:
EventID: 4776
UserName: not null
Workstation: not null
timeframe: 24h
condition: selection | count(UserName) by SourceWorkstation > 3
condition:
- selection1 | count(UserName) by WorkstationName > 3
- selection2 | count(UserName) by Workstation > 3
falsepositives:
- Terminal servers
- Jump servers
@@ -16,11 +16,10 @@ detection:
selection2:
Source: 'Windows Error Reporting'
EventID: 1001
keyword1:
keywords:
- 'MsMpEng.exe'
keyword2:
- 'mpengine.dll'
condition: (selection1 or selection2) and keyword1 and keyword2
condition: 1 of selection* and all of keywords
falsepositives:
- Unknown
level: high
@@ -0,0 +1,31 @@
---
action: global
title: Invocation of Active Directory Diagnostic Tool (ntdsutil.exe)
description: Detects execution of ntdsutil.exe, which can be used for various attacks against the NTDS database (NTDS.DIT)
status: experimental
references:
- https://jpcertcc.github.io/ToolAnalysisResultSheet/details/ntdsutil.htm
author: Thomas Patzke
detection:
selection:
CommandLine: '*\ntdsutil.exe *'
condition: selection
falsepositives:
- NTDS maintenance
level: high
---
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 1
---
logsource:
product: windows
service: security
description: 'Requirements: Audit Policy : Detailed Tracking > Audit Process creation, Group Policy : Administrative Templates\System\Audit Process Creation'
detection:
selection:
EventID: 4688
@@ -2,7 +2,8 @@ title: Suspicious Kerberos RC4 Ticket Encryption
status: experimental
references:
- https://adsecurity.org/?p=3458
description: Detects logons using RC4 encryption type
- https://www.trimarcsecurity.com/single-post/TrimarcResearch/Detecting-Kerberoasting-Activity
description: Detects service ticket requests using RC4 encryption type
logsource:
product: windows
service: security
@@ -10,10 +11,9 @@ detection:
selection:
EventID: 4769
TicketOptions: '0x40810000'
TicketEncryption: '0x17'
TicketEncryptionType: '0x17'
reduction:
- ServiceName: '$*'
- Type: 'Success Audit'
condition: selection and not reduction
falsepositives:
- Service accounts used on legacy systems (e.g. NetApp)
+1 -1
View File
@@ -11,7 +11,7 @@ detection:
EventID: 16
keywords:
- '*\AppData\Local\Temp\SAM-*.dmp *'
condition: selection and keywords
condition: all of them
falsepositives:
- Penetration testing
level: high
@@ -6,11 +6,9 @@ logsource:
service: security
detection:
samrpipe:
- EventLog: Security
EventID: 5145
RelativeTargetName: samr
passwordchanged:
- EventLog: Security
EventID: 4738
PasswordLastSet: (any)
timeframe: 15s
@@ -3,6 +3,7 @@ status: experimental
description: Detects renaming of file while deletion with SDelete tool
author: Thomas Patzke
references:
- https://jpcertcc.github.io/ToolAnalysisResultSheet
- https://www.jpcert.or.jp/english/pub/sr/ir_research.html
- https://technet.microsoft.com/en-us/en-en/sysinternals/sdelete.aspx
logsource:
@@ -10,7 +10,7 @@ detection:
EventID: 4732
GroupName: Administrators
filter:
SubjectAccountName: '*$'
SubjectUserName: '*$'
condition: selection and not filter
falsepositives:
- Legitimate administrative activity
@@ -0,0 +1,32 @@
---
action: global
title: WMI Persistence - Script Event Consumer
status: experimental
description: Detects WMI script event consumers
references:
- https://www.eideon.com/2018-03-02-THL03-WMIBackdoors/
author: Thomas Patzke
date: 2018/03/07
detection:
selection:
Image: 'C:\WINDOWS\system32\wbem\scrcons.exe'
ParentImage: 'C:\Windows\System32\svchost.exe'
condition: selection
falsepositives:
- Legitimate event consumers
level: high
---
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 1
---
logsource:
product: windows
service: security
description: 'Requirements: Audit Policy : Detailed Tracking > Audit Process creation, Group Policy : Administrative Templates\System\Audit Process Creation'
detection:
selection:
EventID: 4688
@@ -26,7 +26,7 @@ detection:
CommandLine: '*.dat,#1'
perfc_keyword:
- '*\perfc.dat*'
condition: fsutil_clean_journal or pipe_com or event_clean or rundll32_dash1 or perfc_keyword
condition: 1 of them
fields:
- CommandLine
- ParentCommandLine
@@ -30,7 +30,7 @@ detection:
- '*bcdedit /set {default} recoveryenabled no*'
- '*wbadmin delete catalog -quiet*'
- '*@Please_Read_Me@.txt*'
condition: selection1 or selection2
condition: 1 of them
fields:
- CommandLine
- ParentCommandLine
+1 -1
View File
@@ -40,7 +40,7 @@ logsource:
detection:
selection:
EventID: 11
TargetFileName:
TargetFilename:
- '*\AppData\Roaming\Oracle\bin\java*.exe'
- '*\Retrive*.vbs'
---
+1 -1
View File
@@ -12,7 +12,7 @@ detection:
- '*icacls * /grant Everyone:F /T /C /Q*'
- '*bcdedit /set {default} recoveryenabled no*'
- '*wbadmin delete catalog -quiet*'
condition: selection1 or selection2
condition: 1 of them
falsepositives:
- Unknown
level: critical
+2 -1
View File
@@ -4,6 +4,7 @@ description: Detects PsExec service installation and execution events (service a
author: Thomas Patzke
references:
- https://www.jpcert.or.jp/english/pub/sr/ir_research.html
- https://jpcertcc.github.io/ToolAnalysisResultSheet
logsource:
product: windows
detection:
@@ -18,7 +19,7 @@ detection:
EventID: 1
Image: '*\PSEXESVC.exe'
User: 'NT AUTHORITY\SYSTEM'
condition: service_installation or service_execution or sysmon_processcreation
condition: 1 of them
fields:
- EventID
- CommandLine
+6 -2
View File
@@ -1,9 +1,10 @@
title: WMI Persistence
status: experimental
description: Detects suspicious WMI event filter and command line event consumer based on event id 5861 (Windows 10, 2012 and higher)
description: Detects suspicious WMI event filter and command line event consumer based on event id 5861 and 5859 (Windows 10, 2012 and higher)
author: Florian Roth
references:
- https://twitter.com/mattifestation/status/899646620148539397
- https://www.eideon.com/2018-03-02-THL03-WMIBackdoors/
logsource:
product: windows
service: wmi
@@ -11,10 +12,13 @@ detection:
selection:
EventID: 5861
keywords:
- 'ActiveScriptEventConsumer'
- 'CommandLineEventConsumer'
- 'CommandLineTemplate'
- 'Binding EventFilter'
condition: selection and 1 of keywords
selection2:
EventID: 5859
condition: selection and 1 of keywords or selection2
falsepositives:
- Unknown (data set is too small; further testing needed)
level: high
@@ -14,7 +14,7 @@ detection:
EventID: 4104
keyword:
- 'PromptForCredential'
condition: selection and keyword
condition: all of them
falsepositives:
- Unknown
level: high
@@ -11,9 +11,9 @@ logsource:
detection:
selection:
EventID: 4103
keywords:
keyword:
- 'PS ATTACK!!!'
condition: selection and keywords
condition: all of them
falsepositives:
- Pentesters
level: high
@@ -16,8 +16,9 @@ detection:
noninteractive:
- ' -noni '
- ' -noninteractive '
condition: encoded and hidden and noninteractive
condition: all of them
falsepositives:
- Penetration tests
- Very special / sneaky PowerShell scripts
level: high
@@ -0,0 +1,33 @@
title: SquiblyTwo
status: experimental
description: Detects WMI SquiblyTwo Attack with possible renamed WMI by looking for imphash
references:
- https://subt0x11.blogspot.ch/2018/04/wmicexe-whitelisting-bypass-hacking.html
- https://twitter.com/mattifestation/status/986280382042595328
author: Markus Neis / Florian Roth
falsepositives:
- Unknown
level: medium
logsource:
product: windows
service: sysmon
detection:
selection1:
EventID: 1
Image:
- '*\wmic.exe'
CommandLine:
- 'wmic * *format:\"http*'
- "wmic * /format:'http"
- 'wmic * /format:http*'
selection2:
EventID: 1
Imphash:
- '1B1A3F43BF37B5BFE60751F2EE2F326E'
- '37777A96245A3C74EB217308F3546F4C'
- '9D87C9D67CE724033C0B40CC4CA1B206'
CommandLine:
- '* *format:\"http*'
- "* /format:'http"
- '* /format:http*'
condition: 1 of them
@@ -0,0 +1,23 @@
title: cmdkey Cached Credentials Recon
status: experimental
description: Detects usage of cmdkey to look for cached credentials.
reference:
- https://www.peew.pw/blog/2017/11/26/exploring-cmdkey-an-edge-case-for-privilege-escalation
- https://technet.microsoft.com/en-us/library/cc754243(v=ws.11).aspx
author: jmallette
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 1
Image: '*\cmdkey.exe'
CommandLine: '* /list *'
condition: selection
fields:
- CommandLine
- ParentCommandLine
- User
falsepositives:
- Legitimate administrative tasks.
level: low
@@ -15,7 +15,7 @@ detection:
dnsregmod:
EventID: 13
TargetObject: '*\services\DNS\Parameters\ServerLevelPluginDll'
condition: dnsadmin or dnsregmod
condition: 1 of them
fields:
- EventID
- CommandLine
@@ -19,7 +19,7 @@ detection:
combination2:
SourceImage: '*\Microsoft Office\*'
CallTrace: '*|UNKNOWN*'
condition: selection and ( combination1 or combination2 )
condition: selection and 1 of combination*
falsepositives:
- unknown
level: high
@@ -22,7 +22,7 @@ detection:
- '*\regsvr32.exe'
- '*\BITSADMIN*'
filter:
Commandline:
CommandLine:
- '*/HP/HP*'
- '*\HP\HP*'
condition: selection and not filter
+8 -1
View File
@@ -3,7 +3,9 @@ status: experimental
description: Detects a Windows command line executable started from Microsoft Word, Excel, Powerpoint, Publisher and Visio.
references:
- https://www.hybrid-analysis.com/sample/465aabe132ccb949e75b8ab9c5bda36d80cf2fd503d52b8bad54e295f28bbc21?environmentId=100
author: Michael Haag
- https://mgreen27.github.io/posts/2018/04/02/DownloadCradle.html
author: Michael Haag, Florian Roth
date: 2018/04/06
logsource:
product: windows
service: sysmon
@@ -16,6 +18,7 @@ detection:
- '*\POWERPNT.exe'
- '*\MSPUB.exe'
- '*\VISIO.exe'
- '*\OUTLOOK.EXE'
Image:
- '*\cmd.exe'
- '*\powershell.exe'
@@ -27,6 +30,10 @@ detection:
- '*\schtasks.exe' # see https://www.hybrid-analysis.com/sample/b409538c99f99b94a5035d9fa44a506b41be0feb23e89b7e4d272ba791aa6002?environmentId=100
- '*\regsvr32.exe' # see https://twitter.com/subTee/status/899283365647458305
- '*\hh.exe' # see https://www.hybrid-analysis.com/sample/6abc2b63f1865a847ff7f5a9d49bb944397b36f5503b9718d6f91f93d60f7cd7?environmentId=100
- '*\wmic.exe' # see https://mgreen27.github.io/posts/2018/04/02/DownloadCradle.html
- '*\mshta.exe' # see https://mgreen27.github.io/posts/2018/04/02/DownloadCradle.html
- '*\rundll32.exe' # see https://mgreen27.github.io/posts/2018/04/02/DownloadCradle.html
- '*\msiexec.exe' # see https://twitter.com/DissectMalware/status/984252467474026497
condition: selection
fields:
- CommandLine
@@ -0,0 +1,31 @@
title: Microsoft Outlook Spawning Windows Shell
status: experimental
description: Detects a Windows command line executable started from Microsoft Outlook
references:
- https://www2.cybereason.com/asset/60:research-cobalt-kitty-attack-lifecycle
author: Florian Roth
date: 2018/03/06
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 1
ParentImage:
- '*\OUTLOOK.EXE'
Image:
- '*\cmd.exe'
- '*\powershell.exe'
- '*\wscript.exe'
- '*\cscript.exe'
- '*\sh.exe'
- '*\bash.exe'
- '*\schtasks.exe'
condition: selection
fields:
- CommandLine
- ParentCommandLine
falsepositives:
- False positives are possible, depends on organisation and processes
level: high
@@ -7,7 +7,7 @@ logsource:
detection:
selection:
EventID: 8
TargetProcess: 'C:\Windows\System32\lsass.exe'
TargetImage: 'C:\Windows\System32\lsass.exe'
StartModule: null
condition: selection
falsepositives:
@@ -1,25 +0,0 @@
title: Suspicious PowerShell Parameter Combination
status: experimental
description: Detects suspicious PowerShell invocation command parameters
author: Florian Roth
logsource:
product: windows
service: sysmon
detection:
keywords:
- 'powershell'
encoded:
- ' -enc '
- ' -EncodedCommand '
hidden:
- ' -w hidden '
- ' -window hidden '
- ' -windowstyle hidden '
noninteractive:
- ' -noni '
- ' -noninteractive '
condition: keywords and encoded and hidden and noninteractive
falsepositives:
- Penetration tests
- Very special / sneaky PowerShell scripts
level: high
@@ -51,7 +51,7 @@ detection:
- ' -encod '
- ' -enco '
- ' -en '
condition: keywords and substrings
condition: all of them
falsepositives:
- Penetration tests
level: high
@@ -13,7 +13,7 @@ detection:
selection:
# Sysmon: File Creation (ID 11)
EventID: 11
TargetFileName: '*\AppData\Local\Temp\SAM-*.dmp*'
TargetFilename: '*\AppData\Local\Temp\SAM-*.dmp*'
condition: selection
falsepositives:
- Unknown
@@ -0,0 +1,35 @@
title: Windows Shell Spawning Suspicious Program
status: experimental
description: Detects a suspicious child process of a Windows shell
references:
- https://mgreen27.github.io/posts/2018/04/02/DownloadCradle.html
author: Florian Roth
date: 20018/04/06
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 1
ParentImage:
- '*\mshta.exe'
- '*\powershell.exe'
- '*\cmd.exe'
- '*\rundll32.exe'
- '*\cscript.exe'
- '*\wscript.exe'
- '*\wmiprvse.exe'
Image:
- '*\schtasks.exe'
- '*\nslookup.exe'
- '*\certutil.exe'
- '*\bitsadmin.exe'
- '*\mshta.exe'
condition: selection
fields:
- CommandLine
- ParentCommandLine
falsepositives:
- Administrative scripts
level: medium
@@ -0,0 +1,36 @@
title: Sticky Key Like Backdoor Usage
description: Detects the usage and installation of a backdoor that uses an option to register a malicious debugger for built-in tools that are accessible in the login screen
references:
- https://blogs.technet.microsoft.com/jonathantrull/2016/10/03/detecting-sticky-key-backdoors/
author: Florian Roth, @twjackomo
date: 2018/03/15
logsource:
product: windows
service: sysmon
detection:
selection_process:
EventID: 1
ParentImage:
- '*\winlogon.exe'
CommandLine:
- '*\cmd.exe sethc.exe *'
- '*\cmd.exe utilman.exe *'
- '*\cmd.exe osk.exe *'
- '*\cmd.exe Magnify.exe *'
- '*\cmd.exe Narrator.exe *'
- '*\cmd.exe DisplaySwitch.exe *'
selection_registry:
EventID: 13
TargetObject:
- '*\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe\Debugger'
- '*\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\utilman.exe\Debugger'
- '*\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\osk.exe\Debugger'
- '*\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Magnify.exe\Debugger'
- '*\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Narrator.exe\Debugger'
- '*\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\DisplaySwitch.exe\Debugger'
EventType: 'SetValue'
condition: 1 of them
falsepositives:
- Unlikely
level: critical
@@ -2,8 +2,7 @@ title: Suspicious Certutil Command
status: experimental
description: Detetcs a suspicious Microsoft certutil execution with sub commands like 'decode' sub command, which is sometimes used to decode malicious code with the built-in certutil utility
author:
- Florian Roth
- juju4
- Florian Roth, juju4
references:
- https://twitter.com/JohnLaTwC/status/835149808817991680
- https://twitter.com/subTee/status/888102593838362624
@@ -0,0 +1,23 @@
title: Ping Hex IP
description: Detects a ping command that uses a hex encoded IP address
references:
- https://github.com/vysec/Aggressor-VYSEC/blob/master/ping.cna
- https://twitter.com/vysecurity/status/977198418354491392
author: Florian Roth
date: 2018/03/23
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 1
CommandLine:
- '*\ping.exe 0x*'
- '*\ping 0x*'
condition: selection
fields:
- ParentCommandLine
falsepositives:
- Unlikely, because no sane admin pings IP addresses in a hexadecimal form
level: high
@@ -22,7 +22,7 @@ detection:
selection3:
EventID: 1
Image: '*\regsvr32.exe'
Commandline:
CommandLine:
- '*/i:http* scrobj.dll'
- '*/i:ftp* scrobj.dll'
# Regsvr32.exe spawned wscript.exe process - indicator of COM scriptlet
@@ -31,7 +31,12 @@ detection:
EventID: 1
Image: '*\wscript.exe'
ParentImage: '*\regsvr32.exe'
condition: selection1 or selection2 or selection3 or selection4
# https://twitter.com/danielhbohannon/status/974321840385531904
selection5:
EventID: 1
Image: '*\EXCEL.EXE'
CommandLine: '*..\..\..\Windows\System32\regsvr32.exe *'
condition: 1 of them
fields:
- CommandLine
- ParentCommandLine
@@ -0,0 +1,17 @@
title: Taskmgr as LOCAL_SYSTEM
status: experimental
description: Detects the creation of taskmgr.exe process in context of LOCAL_SYSTEM
author: Florian Roth
date: 2018/03/18
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 1
User: 'NT AUTHORITY\SYSTEM'
Image: '*\taskmgr.exe'
condition: selection
falsepositives:
- Unkown
level: high
@@ -0,0 +1,24 @@
title: Taskmgr as Parent
status: experimental
description: Detects the creation of a process from Windows task manager
author: Florian Roth
date: 2018/03/13
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 1
ParentImage: '*\taskmgr.exe'
filter:
Image:
- 'resmon.exe'
- 'mmc.exe'
condition: selection and not filter
fields:
- Image
- CommandLine
- ParentCommandLine
falsepositives:
- Administrative activity
level: low
@@ -0,0 +1,20 @@
title: Suspicious TSCON Start
status: experimental
description: Detects a tscon.exe start as LOCAL SYSTEM
reference:
- http://www.korznikov.com/2017/03/0-day-or-feature-privilege-escalation.html
- https://medium.com/@networksecurity/rdp-hijacking-how-to-hijack-rds-and-remoteapp-sessions-transparently-to-move-through-an-da2a1e73a5f6
author: Florian Roth
date: 2018/03/17
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 1
User: 'NT AUTHORITY\SYSTEM'
Image: '*\tscon.exe'
condition: selection
falsepositives:
- Unknown
level: high
@@ -0,0 +1,32 @@
---
action: global
title: Suspicious RDP Redirect Using TSCON
status: experimental
description: Detects a suspicious RDP session redirect using tscon.exe
reference:
- http://www.korznikov.com/2017/03/0-day-or-feature-privilege-escalation.html
- https://medium.com/@networksecurity/rdp-hijacking-how-to-hijack-rds-and-remoteapp-sessions-transparently-to-move-through-an-da2a1e73a5f6
author: Florian Roth
date: 2018/03/17
detection:
selection:
CommandLine: '* /dest:rdp-tcp:*'
condition: selection
falsepositives:
- Unknown
level: high
---
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 1
---
logsource:
product: windows
service: security
description: 'Requirements: Audit Policy : Detailed Tracking > Audit Process creation, Group Policy : Administrative Templates\System\Audit Process Creation'
detection:
selection:
EventID: 4688
@@ -0,0 +1,21 @@
title: Registry Persistence Mechanisms
description: Detects persistence registry keys
references:
- https://oddvar.moe/2018/04/10/persistence-using-globalflags-in-image-file-execution-options-hidden-from-autoruns-exe/
date: 2018/04/11
author: Karneades
logsource:
product: windows
service: sysmon
detection:
selection_reg1:
EventID: 13
TargetObject:
- '*\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\*\GlobalFlag'
- '*\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\*\ReportingMode'
- '*\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\*\MonitorProcess'
EventType: 'SetValue'
condition: 1 of them
falsepositives:
- unknown
level: critical
@@ -0,0 +1,19 @@
title: WMI Persistence - Command Line Event Consumer
status: experimental
description: Detects WMI command line event consumers
references:
- https://www.eideon.com/2018-03-02-THL03-WMIBackdoors/
author: Thomas Patzke
date: 2018/03/07
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 7
Image: 'C:\Windows\System32\wbem\WmiPrvSE.exe'
ImageLoaded: 'wbemcons.dll'
condition: selection
falsepositives:
- Unknown (data set is too small; further testing needed)
level: high
@@ -0,0 +1,18 @@
title: WMI Persistence - Script Event Consumer File Write
status: experimental
description: Detects file writes of WMI script event consumer
references:
- https://www.eideon.com/2018-03-02-THL03-WMIBackdoors/
author: Thomas Patzke
date: 2018/03/07
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 11
Image: 'C:\WINDOWS\system32\wbem\scrcons.exe'
condition: selection
falsepositives:
- Unknown (data set is too small; further testing needed)
level: high
+1
View File
@@ -0,0 +1 @@
{ "query": { "query_string": { "query": $query } } }
+139
View File
@@ -0,0 +1,139 @@
#!/usr/bin/env python3
# CI Test script: generate all queries with es-qs backend and test them against local ES instance.
# Copyright 2018 Thomas Patzke
# 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 asyncio
import functools
import sys
import pprint
import elasticsearch
import elasticsearch_async
pp = pprint.PrettyPrinter()
# Configuration
eshost = "localhost:9200"
index = "test"
sigmac_cmd = "tools/sigmac"
sigmac_processing_prefix = "* Processing Sigma input "
es = elasticsearch.Elasticsearch(hosts=[eshost])
esa = elasticsearch_async.AsyncElasticsearch(hosts=[eshost])
# Create empty test index
try:
es.indices.create(index)
except elasticsearch.exceptions.RequestError as e:
if e.error != 'resource_already_exists_exception': # accept already existing index with same name
raise e
queries = asyncio.Queue()
# sigmac runner coroutinne
async def run_sigmac():
sigmac = asyncio.create_subprocess_exec(
sigmac_cmd, "-t", "es-qs", "-v", "-I", "-r", "rules/",
stdout=asyncio.subprocess.PIPE,
)
print("* Launching sigmac")
proc = await sigmac
print("* sigmac launched with PID {}".format(proc.pid))
cur_rule = None
while True:
line = await proc.stdout.readline()
if not line:
print("* sigmac finished")
await queries.put((None, None))
break
else:
strline = str(line, 'utf-8').rstrip()
if strline.startswith(sigmac_processing_prefix):
cur_rule = strline[len(sigmac_processing_prefix):]
else:
await queries.put((cur_rule, strline))
await proc.wait()
exitcode = proc.returncode
print("* sigmac returned with exit code {}".format(exitcode))
return exitcode
# Generated query checker loop
async def check_queries():
failed = list()
print("# Waiting for queries")
while True:
rule, query = await queries.get()
if query is not None:
print("# Checking query (rule {}): {}".format(rule, query))
result = await esa.indices.validate_query(index=index, q=query)
valid = result['valid']
print("# Received Result for rule {} query={}: {}".format(rule, query, valid))
if not valid:
try:
detail_result = await esa.search(index=index, q=query)
except Exception as e:
error = e.info
failed.append((rule, query, error))
queries.task_done()
else:
queries.task_done()
break
print("# Finished query checks")
return failed
task_check_query = asyncio.ensure_future(check_queries())
task_sigmac = asyncio.ensure_future(run_sigmac())
tasks = [
task_check_query,
task_sigmac
]
loop = asyncio.get_event_loop()
done, pending = loop.run_until_complete(asyncio.wait(tasks))
loop.close()
esa.transport.close()
print()
# Check if sigmac runned successfully
try:
if task_sigmac.result() != 0: # sigmac failed
print("!!! sigmac failed while test!")
sys.exit(1)
except Exception:
print("!!! sigmac failed while test!")
sys.exit(2)
# Check if query checks failed
try:
query_check_result = task_check_query.result()
except Exception:
print("!!! Query check failed!")
sys.exit(3)
query_check_result_cnt = len(query_check_result)
if query_check_result_cnt > 0:
print("!!! {} queries failed to check:".format(query_check_result_cnt))
for rule, query, error in query_check_result:
print("- {}: {}".format(rule, query))
print("Error:")
pp.pprint(error)
print()
sys.exit(4)
else:
print("All query checks passed!")
+93
View File
@@ -0,0 +1,93 @@
logsources:
windows-application:
product: windows
service: application
index: logs-endpoint-winevent-application-*
windows-security:
product: windows
service: security
index: logs-endpoint-winevent-security-*
windows-sysmon:
product: windows
service: sysmon
index: logs-endpoint-winevent-sysmon-*
windows-system:
product: windows
service: system
index: logs-endpoint-winevent-system-*
windows-wmi:
product: windows
service: wmi
index: logs-endpoint-winevent-wmiactivity-*
windows-powershell:
product: windows
service: powershell
index: logs-endpoint-winevent-powershell-*
windows-powershell-classic:
product: windows
service: powershell-classic
index: logs-endpoint-winevent-powershell-*
defaultindex: logs-*
fieldmappings:
AccessMask: object_access_mask_requested
AccountName: service_account_name
AllowedToDelegateTo: user_attribute_allowed_todelegate
AttributeLDAPDisplayName: dsobject_attribute_name
AuditPolicyChanges: policy_changes
AuthenticationPackageName: logon_authentication_package
CallTrace: process_calltrace
CommandLine: command_line
ComputerName: host_name
CurrentDirectory: process_current_directory
DestinationHostname: dst_host
DestinationIp: dst_ip
DestinationIsIpv6: dst_isipv6
DestinationPort: dst_port_number
Details: registry_details
EngineVersion: powershell.engine.version
EventID: event_id
EventType:
EventID=12: registry_event_type
EventID=13: registry_event_type
EventID=14: registry_event_type
EventID=19: wmi_event_type
EventID=20: wmi_event_type
EventID=21: wmi_event_type
FailureCode: ticket_failure_code
GrantedAccess: process_granted_access
GroupName: group_name
HiveName: hive_name
HostVersion: powershell.host.version
Image: process_path
ImageLoaded: image_loaded
LogonProcessName: logon_process_name
LogonType: logon_type
NewProcessName: process_path
ObjectClass: dsobject_class
ObjectName: object_name
ObjectType: object_type
ObjectValueName: object_value_name
OperationType: object_operation_type
ParentImage: process_parent_path
PipeName: pipe_name
ProcessName: process_path
RelativeTargetName: share_relative_target_name
ServiceFileName: service_image_path
ServiceName: service_name
ShareName: share_name
Source: source_name
SourceImage: process_path
StartModule: thread_startmodule
Status: logon_failure_status
SubjectUserName: user_name
TargetFilename: file_name
TargetImage: process_target_path
TargetObject: registry_target_object
TargetImage: target_process_path
TaskName: task_name
TicketEncryptionType: ticket_encryption_type
TicketOptions: ticket_options
User: user
UserName: user_name
Workstation: src_host
WorkstationName: src_host
+1 -1
View File
@@ -24,7 +24,7 @@ fieldmappings:
FailureCode: result_code
GroupName: group_name
KeyLength: key_length
LogonProcess: logon_process
LogonProcessName: logon_process
LogonType: logon_type
ServiceName: service
SubjectAccountName:
+2
View File
@@ -1,5 +1,7 @@
coverage>=4.4.1
PyYAML>=3.11
yamllint>=1.10.0
elasticsearch
elasticsearch-async
setuptools
wheel
+1 -1
View File
@@ -13,7 +13,7 @@ with open(path.join(here, 'README.md'), encoding='utf-8') as f:
setup(
name='sigmatools',
version='0.2',
version='0.4',
description='Tools for the Generic Signature Format for SIEM Systems',
long_description=long_description,
url='https://github.com/Neo23x0/sigma',
+243 -29
View File
@@ -78,6 +78,7 @@ class BaseBackend:
index_field = None # field name that is used to address indices
output_class = None # one of the above output classes
file_list = None
options = tuple() # a list of tuples with following elements: option name, default value, help text, target attribute name (option name if None)
def __init__(self, sigmaconfig, backend_options=None, filename=None):
"""
@@ -87,18 +88,26 @@ class BaseBackend:
super().__init__()
if not isinstance(sigmaconfig, (sigma.config.SigmaConfiguration, None)):
raise TypeError("SigmaConfiguration object expected")
self.options = backend_options
self.backend_options = backend_options
self.sigmaconfig = sigmaconfig
self.sigmaconfig.set_backend(self)
self.output = self.output_class(filename)
# Parse options
for option, default_value, _, target in self.options:
if target is None:
target = option
setattr(self, target, self.backend_options.setdefault(option, default_value))
def generate(self, sigmaparser):
"""Method is called for each sigma rule and receives the parsed rule (SigmaParser)"""
for parsed in sigmaparser.condparsed:
before = self.generateBefore(parsed)
if before is not None:
self.output.print(before, end="")
self.output.print(self.generateQuery(parsed))
query = self.generateQuery(parsed)
if query is not None:
self.output.print(query)
after = self.generateAfter(parsed)
if after is not None:
self.output.print(after, end="")
@@ -193,14 +202,163 @@ class QuoteCharMixin:
class RulenameCommentMixin:
"""Prefixes each rule with the rule title."""
prefix = "# "
options = (
("rulecomment", False, "Prefix generated query with comment containing title", None),
)
def generateBefore(self, parsed):
if "rulecomment" in self.options:
if self.rulecomment:
try:
return "\n%s%s\n" % (self.prefix, parsed.sigmaParser.parsedyaml['title'])
except KeyError:
return ""
class ElasticsearchDSLBackend(RulenameCommentMixin, BaseBackend):
"""ElasticSearch DSL backend"""
identifier = 'es-dsl'
active = True
output_class = SingleOutput
options = (
("es", "http://localhost:9200", "Host and port of Elasticsearch instance", None),
("output", "import", "Output format: import = JSON search request, curl = Shell script that do the search queries via curl", "output_type"),
)
interval = None
title = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.queries = []
def generate(self, sigmaparser):
"""Method is called for each sigma rule and receives the parsed rule (SigmaParser)"""
self.title = sigmaparser.parsedyaml["title"]
self.indices = sigmaparser.get_logsource().index
if len(self.indices) == 0:
self.indices = None
try:
self.interval = sigmaparser.parsedyaml['detection']['timeframe']
except:
pass
for parsed in sigmaparser.condparsed:
self.generateBefore(parsed)
self.generateQuery(parsed)
self.generateAfter(parsed)
def generateQuery(self, parsed):
self.queries[-1]['query']['constant_score']['filter'] = self.generateNode(parsed.parsedSearch)
if parsed.parsedAgg:
self.generateAggregation(parsed.parsedAgg)
# if parsed.parsedAgg:
# fields += self.generateAggregation(parsed.parsedAgg)
# self.fields.update(fields)
def generateANDNode(self, node):
andNode = {'bool': {'must': []}}
for val in node:
andNode['bool']['must'].append(self.generateNode(val))
return andNode
def generateORNode(self, node):
orNode = {'bool': {'should': []}}
for val in node:
orNode['bool']['should'].append(self.generateNode(val))
return orNode
def generateNOTNode(self, node):
notNode = {'bool': {'must_not': []}}
for val in node:
notNode['bool']['must_not'].append(self.generateNode(val))
return notNode
def generateSubexpressionNode(self, node):
return self.generateNode(node.items)
def generateListNode(self, node):
raise NotImplementedError("%s : (%s) Node type not implemented for this backend"%(self.title, 'generateListNode'))
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)))
if type(value) is list:
res = {'bool': {'should': []}}
for v in value:
res['bool']['should'].append({'match': {key: v}})
return res
else:
return {'match': {key: value}}
def generateValueNode(self, node):
return {'multi_match': {'query': node, 'fields': []}}
def generateNULLValueNode(self, node):
return {'missing': {'field': node.item}}
def generateNotNULLValueNode(self, node):
return {'exists': {'field': node.item}}
def generateAggregation(self, agg):
if agg:
if agg.aggfunc == sigma.parser.SigmaAggregationParser.AGGFUNC_COUNT:
if agg.groupfield is not None:
self.queries[-1]['aggs'] = {
'%s_count'%agg.groupfield: {
'terms': {
'field': '%s'%agg.groupfield
},
'aggs': {
'limit': {
'bucket_selector': {
'buckets_path': {
'count': '_count'
},
'script': 'params.count %s %s'%(agg.cond_op, agg.condition)
}
}
}
}
}
else:
for name, idx in agg.aggfuncmap.items():
if idx == agg.aggfunc:
funcname = name
break
raise NotImplementedError("%s : The '%s' aggregation operator is not yet implemented for this backend"%(self.title, funcname))
def generateBefore(self, parsed):
self.queries.append({'query': {'constant_score': {'filter': {}}}})
def generateAfter(self, parsed):
dateField = 'date'
if self.sigmaconfig.config and 'dateField' in self.sigmaconfig.config:
dateField = self.sigmaconfig.config['dateField']
if self.interval:
if 'bool' not in self.queries[-1]['query']['constant_score']['filter']:
self.queries[-1]['query']['constant_score']['filter'] = {'bool': {'must': []}}
if 'must' not in self.queries[-1]['query']['constant_score']['filter']['bool']:
self.queries[-1]['query']['constant_score']['filter']['bool']['must'] = []
self.queries[-1]['query']['constant_score']['filter']['bool']['must'].append({'range': {dateField: {'gte': 'now-%s'%self.interval}}})
def finalize(self):
"""
Is called after the last file was processed with generate(). The right place if this backend is not intended to
look isolated at each rule, but generates an output which incorporates multiple rules, e.g. dashboards.
"""
index = ''
if self.indices is not None and len(self.indices) == 1:
index = '%s/'%self.indices[0]
for query in self.queries:
if self.output_type == 'curl':
self.output.print("\curl -XGET '%s/%s_search?pretty' -H 'Content-Type: application/json' -d'"%(self.es, index))
self.output.print(json.dumps(query, indent=2))
if self.output_type == 'curl':
self.output.print("'")
class SingleTextQueryBackend(RulenameCommentMixin, BaseBackend, QuoteCharMixin):
"""Base class for backends that generate one text-based expression from a Sigma rule"""
identifier = "base-textquery"
@@ -273,9 +431,9 @@ class MultiRuleOutputMixin:
* Unique name by addition of a counter if generated name already in usage
Generated names are tracked by the Mixin.
"""
rulename = sigmaparser.parsedyaml["title"].replace(" ", "-")
rulename = sigmaparser.parsedyaml["title"].replace(" ", "-").replace("(", "").replace(")", "")
if rulename in self.rulenames: # add counter if name collides
cnt = 2
while "%s-%d" % (rulename, cnt) in self.rulenames:
@@ -292,7 +450,7 @@ class ElasticsearchQuerystringBackend(SingleTextQueryBackend):
identifier = "es-qs"
active = True
reEscape = re.compile("([+\\-=!(){}\\[\\]^\"~:\\\\/]|&&|\\|\\|)")
reEscape = re.compile("([+\\-=!(){}\\[\\]^\"~:/]|\\\\(?![*?])|\\\\u|&&|\\|\\|)")
reClear = re.compile("[<>]")
andToken = " AND "
orToken = " OR "
@@ -311,10 +469,17 @@ class KibanaBackend(ElasticsearchQuerystringBackend, MultiRuleOutputMixin):
identifier = "kibana"
active = True
output_class = SingleOutput
options = (
("output", "import", "Output format: import = JSON file manually imported in Kibana, curl = Shell script that imports queries in Kibana via curl (jq is additionally required)", "output_type"),
("es", "localhost:9200", "Host and port of Elasticsearch instance", None),
("index", ".kibana", "Kibana index", None),
("prefix", "Sigma: ", "Title prefix of Sigma queries", None),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.kibanaconf = list()
self.indexsearch = set()
def generate(self, sigmaparser):
rulename = self.getRuleName(sigmaparser)
@@ -345,12 +510,16 @@ class KibanaBackend(ElasticsearchQuerystringBackend, MultiRuleOutputMixin):
if len(indices) > 1: # add index names if rule must be replicated because of ambigiuous index patterns
raise NotSupportedError("Multiple target indices are not supported by Kibana")
else:
title = sigmaparser.parsedyaml["title"]
try:
title = self.options["prefix"] + title
except KeyError:
pass
title = self.prefix + sigmaparser.parsedyaml["title"]
self.indexsearch.add(
"export {indexvar}=$(curl -s '{es}/{index}/_search?q=index-pattern.title:{indexpattern}' | jq -r '.hits.hits[0]._id | ltrimstr(\"index-pattern:\")')".format(
es=self.es,
index=self.index,
indexpattern=index.replace("*", "\\*"),
indexvar=self.index_variable_name(index)
)
)
self.kibanaconf.append({
"_id": final_rulename,
"_type": "search",
@@ -362,7 +531,7 @@ class KibanaBackend(ElasticsearchQuerystringBackend, MultiRuleOutputMixin):
"sort": ["@timestamp", "desc"],
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": json.dumps({
"searchSourceJSON": {
"index": index,
"filter": [],
"highlight": {
@@ -379,32 +548,53 @@ class KibanaBackend(ElasticsearchQuerystringBackend, MultiRuleOutputMixin):
}
}
}
)
}
}
})
def finalize(self):
self.output.print(json.dumps(self.kibanaconf, indent=2))
if self.output_type == "import": # output format that can be imported via Kibana UI
for item in self.kibanaconf: # JSONize kibanaSavedObjectMeta.searchSourceJSON
item['_source']['kibanaSavedObjectMeta']['searchSourceJSON'] = json.dumps(item['_source']['kibanaSavedObjectMeta']['searchSourceJSON'])
self.output.print(json.dumps(self.kibanaconf, indent=2))
elif self.output_type == "curl":
for item in self.indexsearch:
self.output.print(item)
for item in self.kibanaconf:
item['_source']['kibanaSavedObjectMeta']['searchSourceJSON']['index'] = "$" + self.index_variable_name(item['_source']['kibanaSavedObjectMeta']['searchSourceJSON']['index']) # replace index pattern with reference to variable that will contain Kibana index UUID at script runtime
item['_source']['kibanaSavedObjectMeta']['searchSourceJSON'] = json.dumps(item['_source']['kibanaSavedObjectMeta']['searchSourceJSON']) # Convert it to JSON string as expected by Kibana
item['_source']['kibanaSavedObjectMeta']['searchSourceJSON'] = item['_source']['kibanaSavedObjectMeta']['searchSourceJSON'].replace("\\", "\\\\") # Add further escaping for escaped quotes for shell
self.output.print(
"curl -s -XPUT -H 'Content-Type: application/json' --data-binary @- '{es}/{index}/doc/{doc_id}' <<EOF\n{doc}\nEOF".format(
es=self.es,
index=self.index,
doc_id="search:" + item['_id'],
doc=json.dumps({
"type": "search",
"search": item['_source']
}, indent=2)
)
)
else:
raise NotImplementedError("Output type '%s' not supported" % self.output_type)
def index_variable_name(self, index):
return "index_" + index.replace("-", "__").replace("*", "X")
class XPackWatcherBackend(ElasticsearchQuerystringBackend, MultiRuleOutputMixin):
"""Converts Sigma Rule into X-Pack Watcher JSON for alerting"""
identifier = "xpack-watcher"
active = True
output_class = SingleOutput
options = (
("output", "curl", "Output format: curl = Shell script that imports queries in Watcher index with curl", "output_type"),
("es", "localhost:9200", "Host and port of Elasticsearch instance", None),
("mail", None, "Mail address for Watcher notification (only logging if not set)", None),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.watcher_alert = dict()
try:
self.output_type = self.options["output"]
except KeyError:
self.output_type = "curl"
try:
self.es = self.options["es"]
except KeyError:
self.es = "localhost:9200"
def generate(self, sigmaparser):
# get the details if this alert occurs
@@ -512,7 +702,7 @@ class XPackWatcherBackend(ElasticsearchQuerystringBackend, MultiRuleOutputMixin)
# Building the action
action_subject = "Sigma Rule '%s'" % title
try: # mail notification if mail address is given
email = self.options['mail']
email = self.mail
action = {
"send_email": {
"email": {
@@ -583,7 +773,7 @@ class LogPointBackend(SingleTextQueryBackend):
identifier = "logpoint"
active = True
reEscape = re.compile('(["\\\\])')
reEscape = re.compile('("|\\\\(?![*?]))')
reClear = None
andToken = " "
orToken = " OR "
@@ -597,7 +787,7 @@ class LogPointBackend(SingleTextQueryBackend):
mapExpression = "%s=%s"
mapListsSpecialHandling = True
mapListValueExpression = "%s IN %s"
def generateAggregation(self, agg):
if agg == None:
return ""
@@ -607,14 +797,14 @@ class LogPointBackend(SingleTextQueryBackend):
return " | chart %s(%s) as val | search val %s %s" % (agg.aggfunc_notrans, agg.aggfield, agg.cond_op, agg.condition)
else:
return " | chart %s(%s) as val by %s | search val %s %s" % (agg.aggfunc_notrans, agg.aggfield, agg.groupfield, agg.cond_op, agg.condition)
class SplunkBackend(SingleTextQueryBackend):
"""Converts Sigma rule into Splunk Search Processing Language (SPL)."""
identifier = "splunk"
active = True
index_field = "index"
reEscape = re.compile('(["\\\\])')
reEscape = re.compile('("|\\\\(?![*?]))')
reClear = None
andToken = " "
orToken = " OR "
@@ -689,8 +879,15 @@ class FieldnameListBackend(BaseBackend):
active = True
output_class = SingleOutput
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields = set()
def generateQuery(self, parsed):
return "\n".join(sorted(set(list(flatten(self.generateNode(parsed.parsedSearch))))))
fields = list(flatten(self.generateNode(parsed.parsedSearch)))
if parsed.parsedAgg:
fields += self.generateAggregation(parsed.parsedAgg)
self.fields.update(fields)
def generateANDNode(self, node):
return [self.generateNode(val) for val in node]
@@ -718,6 +915,23 @@ class FieldnameListBackend(BaseBackend):
def generateValueNode(self, node):
return []
def generateNULLValueNode(self, node):
return [node.item]
def generateNotNULLValueNode(self, node):
return [node.item]
def generateAggregation(self, agg):
fields = list()
if agg.groupfield is not None:
fields.append(agg.groupfield)
if agg.aggfield is not None:
fields.append(agg.aggfield)
return fields
def finalize(self):
self.output.print("\n".join(sorted(self.fields)))
# Helpers
def flatten(l):
for i in l:
+31 -7
View File
@@ -101,8 +101,9 @@ class SigmaParser:
def parse_sigma(self):
try: # definition uniqueness check
for definitionName, definition in self.parsedyaml["detection"].items():
self.definitions[definitionName] = definition
self.extract_values(definition) # builds key-values-table in self.values
if definitionName != "condition":
self.definitions[definitionName] = definition
self.extract_values(definition) # builds key-values-table in self.values
except KeyError:
raise SigmaParseError("No detection definitions found")
@@ -283,7 +284,7 @@ class SigmaConditionTokenizer:
(SigmaConditionToken.TOKEN_AND, re.compile("and", re.IGNORECASE)),
(SigmaConditionToken.TOKEN_OR, re.compile("or", re.IGNORECASE)),
(SigmaConditionToken.TOKEN_NOT, re.compile("not", re.IGNORECASE)),
(SigmaConditionToken.TOKEN_ID, re.compile("\\w+")),
(SigmaConditionToken.TOKEN_ID, re.compile("[\\w*]+")),
(SigmaConditionToken.TOKEN_LPAR, re.compile("\\(")),
(SigmaConditionToken.TOKEN_RPAR, re.compile("\\)")),
]
@@ -417,13 +418,36 @@ class NodeSubexpression(ParseTreeNode):
self.items = subexpr
# Parse tree converters: convert something into one of the parse tree node classes defined above
def convertXOf(sigma, val, condclass):
"""
Generic implementation of (1|all) of x expressions.
* condclass across all list items if x is name of definition
* condclass across all definitions if x is keyword 'them'
* condclass across all matching definition if x is wildcard expression, e.g. 'selection*'
"""
if val.matched == "them": # OR across all definitions
cond = condclass()
for definition in sigma.definitions.values():
cond.add(NodeSubexpression(sigma.parse_definition(definition)))
return NodeSubexpression(cond)
elif val.matched.find("*") > 0: # OR across all matching definitions
cond = condclass()
reDefPat = re.compile("^" + val.matched.replace("*", ".*") + "$")
for name, definition in sigma.definitions.items():
if reDefPat.match(name):
cond.add(NodeSubexpression(sigma.parse_definition(definition)))
return NodeSubexpression(cond)
else: # OR across all items of definition
return NodeSubexpression(sigma.parse_definition_byname(val.matched, condclass))
def convertAllOf(sigma, op, val):
"""Convert 'all of x' into ConditionAND"""
return NodeSubexpression(sigma.parse_definition_byname(val.matched, ConditionAND))
"""Convert 'all of x' expressions into ConditionAND"""
return convertXOf(sigma, val, ConditionAND)
def convertOneOf(sigma, op, val):
"""Convert '1 of x' into ConditionOR"""
return NodeSubexpression(sigma.parse_definition_byname(val.matched, ConditionOR))
"""Convert '1 of x' expressions into ConditionOR"""
return convertXOf(sigma, val, ConditionOR)
def convertId(sigma, op):
"""Convert search identifiers (lists or maps) into condition nodes according to spec defaults"""
+13 -1
View File
@@ -54,7 +54,19 @@ def get_inputs(paths, recursive):
else:
return [pathlib.Path(p) for p in paths]
argparser = argparse.ArgumentParser(description="Convert Sigma rules into SIEM signatures.")
class SigmacArgumentParser(argparse.ArgumentParser):
def format_help(self):
helptext = super().format_help() + "\nBackend options:\n"
for backend in backends.getBackendList():
if len(backend.options) > 0:
helptext += " " + backend.identifier + "\n"
for option, default, help, _ in backend.options:
helptext += " {:10}: {} (default: {})".format(option, help, default) + "\n"
return helptext
argparser = SigmacArgumentParser(description="Convert Sigma rules into SIEM signatures.")
argparser.add_argument("--recurse", "-r", action="store_true", help="Recurse into subdirectories (not yet implemented)")
argparser.add_argument("--filter", "-f", help="""
Define comma-separated filters that must match (AND-linked) to rule to be processed.