If you are reading this blog post via a 3rd party source it is very likely that many parts of it will not render correctly (usually, the interactive graphs). Please view the post on dogesec.com for the full interactive viewing experience.
tl;dr
As a detection engineer, you likely work with various SIEM or XDR tools.
This is problematic because it adds a large amount of friction to the sharing detection content.
What is needed is a detection rule standard. A way to write a query once and use it everywhere, on any system.
That is the ambitious aim of the Sigma project.
Sigma has been around for about three years. Though in the last year it has seen a marked increase in adoption.
Sigma is for log files what Snort is for network traffic and YARA is for files.
The Sigma Rule format has been designed to accommodate for conversion into other query languages to match the systems on which they will be used. For example, a Sigma Rule could be translated into Splunk’s query language, SPL, or Google Chronicle’s YARA-L 2.0 queries.
The aim of this post is to get you to a point where you’re comfortable with writing Sigma Rules.
How we ended up here
Our intelligence team first started considering Sigma when we ran into limitations with STIX Patterns (a STIX specific detection language).
I have previously written about writing STIX Patterns on the blog.
Whilst STIX Patterns allow for behavioural based detections, they quickly start running into limitations in more complex scenarios.
As an example, lets say we would like to detect the use of several reconnaissance commands in quick succession using STIX Patterns. Each command alone is not suspicious but together they may indicate reconnaissance activity.
For example;
([process:command_line LIKE ‘auser%’] AND [process:command_line LIKE ‘dir%’] AND [process:command_line LIKE ‘net%’]) WITHIN 30 SECONDS
Although this pattern may look like it is doing what we want, there is a major issue; there is no way to limit the scope of events this detection applies to.
When you’re monitoring the entire network what this really means is: auser
anywhere AND dir
anywhere AND net
anywhere WITHIN 30 SECONDS
. This detection is far too wide, it should really be more targetted applying this logic to the same hostname and/or potentially the same user within this time range.
Whilst STIX is the best solution for modelling threat intelligence, it is clearly not for detections.
Given the open standard, flexibility of rule creation, and ecosystem around Sigma, we quickly realised it was what we needed…
The Basics of Sigma Rules
Sigma Rules are structured in a YAML format.
The Sigma Rule v2.0 specification is split into three parts;
- Sigma Rules Specification: the core spec
- Sigma Filters Specification: how to apply filters to suppress matches across multiple Sigma Rules (e.g. useful for environment specific tuning where a false positive prone application is used in an organisation and its false positives are accepted.)
- Sigma Correlation Rules Specification: a more advanced way to create detection logic across multiple rules
In this post I’m going to focus on the core specification.
Preparing to write a rule
When writing Sigma Rules, I find it helpful to think of a Sigma Rules in sections;
- Metadata: information that helps classify the rule
- Log sources: describes the log data on which the detection is meant to be applied to
- Detection: the logic to identify something in the log
1. Metadata
1.1 General info
The main purpose of these properties is to help manage and maintain rules.
My advice would be to take a look at some existing Sigma Rules to see some example values used for these properties, but here’s a short overview of them;
id
(optional): a UUIDv4 to identify the rulerelated
(optional): To be able to keep track of the relationships between detections, Sigma rules may also contain references to related rule identifiers in the related attribute.name
(optional): a unique machine-readable name that can be used instead of the id as a reference in correlation rules (e.g.failed_logins
)title
(required): A brief title for the rule that should contain what the rule is supposed to detectdescription
(optional): A short and accurate description of the rule and the malicious or suspicious activity that can be detectedstatus
(optional): Declares the status of the rule. Dictionary of options available here.license
(optional): License of the rule according the SPDX ID specification.author
(optional): Creator of the rule. (can be a name, nickname, twitter handle…etc)references
(optional): References to the sources that the rule was derived from.date
(optional): Creation date of the rule.modified
(optional): Last modification date of the rule.level
(optional): The level field contains one of five values listed here. It describes the criticality of a triggered rule.tags
(optional): A Sigma rule can be categorized with tags, some are standardised
1.2 Versioning
To track when Sigma Rules are updated the date
(the date the rule was created) and modified
(the date it was last modified) values can be used in the format YYYY-MM-DD
.
For example;
id: 929a690e-bef0-4204-a928-ef5e620d6fcc
title: Test rule
date: 2025-01-01
modified: 2022-01-01
Reasons to change the modified date:
- changed title
- changed detection section
- changed level
- changed logsource (rare)
- changed status to deprecated
1.3 Linking rules
To keep track of relationships between rules, Sigma rules may also contain references to related
rule id
s along with the description of the relationships using the list of options here. For example;
id: 929a690e-bef0-4204-a928-ef5e620d6fcc
related:
- id: 08fbc97d-0a2f-491c-ae21-8ffcfd3174e9
type: derived
- id: 929a690e-bef0-4204-a928-ef5e620d6fcc
type: obsoletes
Here the current rule (929a690e-bef0-4204-a928-ef5e620d6fcc
) is derived from another rule (08fbc97d-0a2f-491c-ae21-8ffcfd3174e9
) and replaces (obsoletes) a rule (929a690e-bef0-4204-a928-ef5e620d6fcc
).
This can also be used to link rules. For example, those detecting the same thing (e.g. a Vulnerability).
1.4 Tags
A Sigma rule can be categorised with tags. Tags can be anything, but Sigma ships with some predefined tags which I’d recommend you use where possible (or sending a pull request / creating an issue to the Sigma repo with proposals for new tags).
A tag ultimately provides more contextual information about the rule.
Tags are namespaced, (a .
is used as separator, e.g. attack.t1059.001
, here attack
is the namespace).
Predefined Sigma tags include;
attack.
: MITRE ATT&CKtlp.
Traffic Light Protocolcve.
NVD CVEs
Here’s an example;
tags:
- attack.defense_evasion
- attack.t1027
- attack.execution
- attack.t1059.001
- car.2016-04-005
- tlp.amber
- not.a-defined-tag
1.5 In summary
To demonstrate these properties, here is a partial rule (without log sources or the detection defined)
id: 929a690e-bef0-4204-a928-ef5e620d6fcc
related:
- id: 08fbc97d-0a2f-491c-ae21-8ffcfd3174e9
type: derived
- id: 929a690e-bef0-4204-a928-ef5e620d6fcc
type: obsoletes
title: Demo rule
description: Just showing off metadata properties
author: David Greenwood
date: 2025-01-01
modified: 2025-01-01
status: unsupported
license: Apache-2.0
level: informational
references:
- https://www.dogesec.com
- https://www.github.com/muchdogesec
tags:
- attack.defense_evasion
- attack.t1027
2. Log sources
The logsource
attribute describes the log data on which the detection is meant to be applied. It is useful for the rule convertors to determine the indexes and data sources the detection should be applied to.
When I talk about convertors in this post, I am talking about code that translates a Sigma rule into another detection language (see: pySigma).
logsource
is made up of the following attributes;
category
:- used to select all log files written by a certain group of products, like firewalls or web server logs.
- e.g.
firewall
,web
,antivirus
- e.g.
- used to select all log files written by a certain group of products, like firewalls or web server logs.
product
:- used to select all log outputs of a certain product, e.g. all Windows Eventlog types including “Security”, “System”, “Application” and the new log types like “AppLocker” and “Windows Defender”.
- e.g.
windows
,apache
- e.g.
- used to select all log outputs of a certain product, e.g. all Windows Eventlog types including “Security”, “System”, “Application” and the new log types like “AppLocker” and “Windows Defender”.
service
:- used to select only a subset of a product’s logs, like the “sshd” on Linux or the “Security” Eventlog on Windows systems.
- e.g.
sshd
,applocker
- e.g.
- used to select only a subset of a product’s logs, like the “sshd” on Linux or the “Security” Eventlog on Windows systems.
definition
- used to describe the logsource, including some information on the log verbosity level or configurations that have to be applied (e.g.
Script Block Logging must be enabled
. Note, unlike the otherlogsource
properties,definition
is not considered by convertors and is designed to provide helpful information to those reading the rule.- e.g.
INFO
,DEBUG
- e.g.
- used to describe the logsource, including some information on the log verbosity level or configurations that have to be applied (e.g.
You can use the values of category
, product
and service
to point the converters to a certain index.
For example,
logsource:
category: firewall
Then in the convertor configuration files, it can be defined that the category
firewall
converts to ( index=fw1* OR index=asa* )
during Splunk search conversion.
Or,
logsource:
product: windows
Here, the product
windows
could be converted to "_index":"logstash-windows*"
in Elasticsearch queries.
A list of standard logsources can be viewed here.
Generally, you’ll want to use a pre-existing logsource. Of course, if a log source does not exist for your log type, most likely when custom products, logs, or field naming is used, then you can specify a non-standard logsource using the logic defined.
Sigma does not restrict what a Sigma logsource can be defined as, meaning you can use Sigma for just about any kind of logsource within your SIEM.
Sigma compiles the logsource
sub-attributes using AND
statements. Take this example;
logsource:
product: aws
service: cloudtrail
Here it is saying the logsource
must be; product: aws
AND service: cloudtrail
. This will then apply all settings for product
and service
defined in the convertors.
The advantages of this abstract approach is that it does not limit the rule to a specific telemetry source.
Instead creating multiple rules for the different telemetry sources such as Sysmon
, Microsoft-Windows-Security-Auditing
, Microsoft-Windows-Kernel-Process
and all the other possible product-specific sources, a generic log source may be used which is then handled by the convertors.
e.g.
category: process_creation
product: windows
3. Detection
The detection
section contains the core logic that identifies specific events and behaviours within the logsources
deemed to something worth detecting.
The detection
section contains a set of sub-attributes that represent searches on log data and how they should be evaluated:
- Selections: What you actually wish to select/search from the log data
- Conditions: How should the Selections or filters are to be evaluated
As a simple example, a selection could define a range of strings to search for in the logs (e.g. process IDs) while the condition could define how many of the process ID must be seen to trigger the detection.
This is a really simple example, both the selections and conditions can be used to perform much more advanced used cases.
Let me demonstrate…
3.1 Selections
3.1.1: Selections: Lists
Lists are the simplest way to define a selection. They contain strings that are applied to the full log message and are linked with a logical OR
statement.
logsource:
product: windows
service: system
detection:
selection:
- 4728
- 4729
- 4730
condition: selection
In this example, selection
matches events containing 4728
OR
4729
OR
4730
.
The naming of the attribute selection
in this example is arbitrary (it could be anything).
For example, this detection would work in the same way;
logsource:
product: windows
service: system
detection:
keywords:
- 4728
- 4729
- 4730
condition: keywords
Of course, it is a good idea that the selection attribute names are descriptive and obvious to the reader.
The rule above is simple, and very inefficient because no field names are defined. It is simply searching for a list of strings in the logs.
3.1.2: Selections: Field Lists
That’s where we can search by field list. For example, lets narrow the last rule down to only search for the specified values in a field called EventID
…
logsource:
product: windows
service: system
detection:
selection:
EventID:
- 4728
- 4729
- 4730
condition: selection
For example, now only the EventID
field in downstream tools will be searched for the values 4728
OR
4729
OR
4730
.
Note, field names are case sensitive. EventID
and eventid
are two different values.
You can also use key: value
selections to search for single fields. For example,
logsource:
product: windows
service: system
detection:
selection:
EventID: 6416
condition: selection
You can also pass multiple fields (that are joined with an AND
statement);
logsource:
product: windows
service: system
detection:
selection:
EventID: 6416
ClassName: DiskDrive
condition: selection
In this example I am matching on any events where the EventID=6416
AND
the ClassName=DiskDrive
. I could add more field/values to filter on, if needed.
You can also combine these concepts together.
logsource:
product: windows
service: system
detection:
selection:
EventLog: Security
EventID:
- 517
- 1102
condition: selection
Here the selection matches on Eventlog=Security
AND
( EventID=517
OR
EventID=1102
).
3.1.3: Selections: Special values
You should be aware there are special field values that can be used for values.
- An empty value is defined with
''
- A non-existent value is defined with
null
To demonstrate…
logsource:
product: windows
service: system
detection:
selection:
EventLog: Security
EventID: ''
condition: selection
Would mean EventID
field should be present, but have no value.
logsource:
product: windows
service: system
detection:
selection:
EventLog: Security
EventID: null
condition: selection
Would mean the EventID
should not be present.
3.1.4: Selections: Wildcards
You can also use wildcards in the value string. For example using *
to replace an unbounded length wildcard;
logsource:
product: windows
service: system
detection:
selection:
EventLog: Security
EventID: 5*
condition: selection
Would match on any EventID
starting with 5
(e.g. 500
, 5121
, etc.)
?
is used to replace a single mandatory character, for example;
logsource:
product: windows
service: system
detection:
selection:
FileName: prog?.exe
condition: selection
Would match on any FileName
where the ?
had a value (e.g. prog1.exe
, prog2.exe
, proga.exe
but not rogram.exe
)
The backslash character \
is used for escaping of wildcards *
and ?
as well as the backslash character itself. Escaping of the backslash is necessary if it is followed by a wildcard depending on the desired result.
For example, if you wanted to match on a value ?
or *
, you’d need to use a \
to show that it should not be used as a wildcard,
logsource:
product: windows
service: system
detection:
keywords:
- question\?
- star\*
condition: selection
Would match on the literal values question? or star*
.
Similarly, if a backslash is to be matched on (e.g. a Windows path) it also needs to be escaped.
logsource:
product: windows
service: system
detection:
selection:
FilePath: \\example.exe
condition: selection
Would match on the value \example.exe
.
3.1.5: Selections: Modifiers
The values contained in Sigma rules can be modified by value modifiers. Value modifiers are appended after the field name with a pipe character |
as separator and can also be chained, e.g. fieldname|mod1|mod2: value
. The value modifiers are applied in the given order to the value.
Modifiers can make the selections much more flexible.
3.1.5.1: Selections: Modifiers: contains
contains
which puts *
wildcards around the values, such that the value is matched anywhere in the field. Here is an example;
detection:
selection:
CommandLine|contains:
- DumpCreds
- invoke-mimikatz
condition: selection
This is the same as using:
detection:
selection:
CommandLine:
- *DumpCreds*
- *invoke-mimikatz*
condition: selection
It’s also important to point out how modifiers are written – they are appended after the field name with a |
character.
In the first example, the selection matches the CommandLine
field in the log data and uses the Transformation Modifier contains
in order to check if the keywords DumpCreds
OR invoke-mimikatz
are present in the field.
For example this detection would match on CommandLine="Has detected DumpCreds"
OR CommandLine="DumpCreds"
OR CommandLine="now invoke-mimikatz"
If I did not use the contains
Value Modifier like so;
detection:
selection:
CommandLine:
- DumpCreds
- invoke-mimikatz
condition: selection
Now only an exact match for the CommandLine
field would match. This would be either CommandLine="DumpCreds"
OR CommandLine="invoke-mimikatz"
. CommandLine="Has detected DumpCreds"
would not match.
3.1.5.2: Selections: Modifiers: startswith
/ endswith
You might want to use a more specific Transformation Modifier, like startswith
OR endswith
.
detection:
selection:
CommandLine|startswith:
- DumpCreds
- invoke-mimikatz
condition: selection
Here the CommandLine
field in the event must start with either DumpCreds
OR invoke-mimikatz
.
detection:
selection:
CommandLine|endswith:
- DumpCreds
- invoke-mimikatz
condition: selection
Here the CommandLine
field in the event must end with either DumpCreds
OR invoke-mimikatz
.
3.1.5.3: Selections: Modifiers: all
The all
Transformation Modifier can also prove very useful on occasion. As noted, Lists of values are treated by default using the logical OR
statement. This modifier changes this to AND
.
detection:
selection|all:
- DumpCreds
- invoke-mimikatz
condition: selection
In this example, I am now saying the levent must have both DumpCreds
AND invoke-mimikatz
in its value (note I don’t select a field name in this detection, as I did in previous examples).
3.1.5.4: Selections: Modifiers: exists
In some case a field can be optional in the event. You can use the exists
modifiers to check it.
detection:
selection:
EventID: 4738
PasswordLastSet|exists: true
condition: selection
Checks the log contains a PasswordLastSet
field.
exists
is a boolean modified, it must be set to either true
or false
.
3.1.5.5: Selections: Modifiers: cased
Default Sigma behavior is case-insensitive matching, cased
will observe the case of the value entered, e.g.
detection:
selection:
username|cased: david
condition: selection
Will only match where the log contains a username
value equal to david
. It won’t match if it’s DAVID
.
3.1.5.6: Selections: Modifiers: gt
/ gte
/ lt
/ lte
Greater than (gt
), greater or equal to gte
, less than (lt
), and less than or equal to lte
, are useful modifiers when working with numerical values.
detection:
selection:
port|gte: 8000
port|lte: 9000
condition: selection
Here the rule will match if the value for the port
field is between 8000
and 9000
3.1.5.7: Selections: Modifiers: windash
Creates all possible permutations of the -
, /
, –
(en dash), —
(em dash), and ―
(horizontal bar) characters.
This is incredibly useful in the the Windows ecosystem, where Windows has two standards for passing arguments to commands, usually -
for PowerShell (e.g. -a
), and /
for cmd.exe
(e.g. /a
), but a large number of commands will commonly accept both. Many tools, including PowerShell, will not only accept a normal hyphen, but other similar looking dashes.
detection:
selection:
CommandLine|windash|contains:
- '-s '
- '-f '
- '-t '
- '-m '
- '-a '
- '-u '
Here -s
would be searched as /s
, -s
, ―s
etc, in the log. The same is true for other items in the list.
As you can see above, Modifiers can also be chained using a |
, (e.g. fieldname|mod1|mod2:
). The value modifiers are applied in the given order to the value.
This example logically reads the CommandLine
field should be searched for one of the list items after the dash is replaced with a forward slash, and the search should consider that the field contains the converted value.
3.1.5.8: Selections: Modifiers: base64offset
/ base64
The base64
modifier-set will encode the provided values as base64 encoded strings. Often used alongside contains to identify malicious injection into applications.
detection:
selection:
fieldname|base64offset|contains:
- /bin/bash
- /bin/sh
- /bin/zsh
condition: selection
e.g. /bin/bash
would be encoded as base64 and the base64 value (L2Jpbi9iYXNo
) would what would be searched in the logs. So this search could be written as;
detection:
selection:
fieldname|contains:
- L2Jpbi9iYXNo
- L2Jpbi9zaA==
- L2Jpbi96c2g=
condition: selection
3.1.5.9: Selections: Modifiers: cidr
The cidr modifier allows for CIDR-formatted subnets to be used as field values, where any IPv4 or IPv6 addresses are supported.
detection:
selection:
first_ip_address|cidr: 192.0.0.0/8
second_ip_address|cidr: 192.168.0.0/23
condition: selection
This query will trigger if any IP addresses in range 192.0.0.0/8
(16,777,216 IP addresses) AND any IP addresses in the range 192.168.0.0/23
(512 IP addresses) are found in the event.
3.1.5.10: Selections: Modifiers: re
Sometimes specific do not quite suit what you are trying to achieve, particularly with more complex/varying values that need to be detected.
You can use the Regular Expression (re
) modifier for pattern based matching. Here is an example of it being used;
detection:
search_identifier_1:
- CommandLine|re: '\$PSHome\[\s*\d{1,3}\s*\]\s*\+\s*\$PSHome\['
- CommandLine|re: '\$ShellId\[\s*\d{1,3}\s*\]\s*\+\s*\$ShellId\['
- CommandLine|re: '\$env:Public\[\s*\d{1,3}\s*\]\s*\+\s*\$env:Public\['
condition: search_identifier_1
Here the event CommandLine
field values must match at least one of the Regular Expressions defined.
You might be tempted to use the Regular Expressions Type Modifier a lot, though avoid it where possible (as it can create downstream conversion issues).
3.1.5.11: Selections: Modifiers: more modifiers
I’ve only covered the most common modifier above. Other options for more advanced use-case are;
expand
fieldref
utf16
/utf16le
/utf16be
/wide
You can read more about these here.
3.1.6 What field name do I use?
Theoretically you can use whatever field names you wish, as long as someone is willing to put in the time to write a Sigma taxonomy to define the fields.
By default the Sigma taxonomy, defined here will be used.
If your logsource and/or field name is not listed there, you will need to create a custom taxonomy.
A taxonomy can define:
- field names, example:
process_command_line
instead ofCommandLine
. - field values, example: a field
image_file_name
that only contains a file name likeexample.exe
and is transformed intoImageFile: *\\example.exe
. - logsource names, example:
category: ProcessCreation
instead ofcategory: process_creation
The custom taxonomy can be defined in the rule itself under the taxonomy
property.
I won’t go into any more detail in this post, as I’d consider this fairly advanced usage of Sigma. The default Sigma taxonomy is broad enough to get you started.
3.2 Conditions
So far I’ve only covered one selection in a rule. In fact, a Sigma Rule detection can have many selections.
That’s where conditions come into play.
For example;
detection:
selection_1:
Image|endswith: '/bash'
CommandLine|contains:
- DumpCreds
- invoke-mimikatz
selection_2:
CommandLine|contains:
- rpc
- token
- crypto
selection_3:
CommandLine|contains:
- bitcoin
condition: selection_1 OR selection_2 OR selection_3
Here I use three selections in the condition
.
The condition
property defines the combinations of selections that should trigger a detection.
In this case, if one of the three conditions (selection_1 OR selection_2 OR selection_3
) is true, then a detection should be triggered.
Essentially this detection reads;
(`Image|endswith = '/bash'` AND (`CommandLine CONTAINS DumpCreds` OR `CommandLine CONTAINS invoke-mimikatz`)) OR
(`CommandLine CONTAINS rpc` OR `CommandLine CONTAINS token` OR `CommandLine CONTAINS crypto`) OR
(`CommandLine CONTAINS bitcoin`)
Conditions can be defined using a variety of operators.
Operators that can prove useful in tuning the extensibility and accuracy a rule by describing how the selections should be considered. We’ve already covered two…
- Exact match
- e.g.
selection_1
- e.g.
- Logical
AND
/OR
- e.g.
selection_1 OR selection_2
- e.g.
selection_1 AND selection_2
- e.g.
Other options include…
3.2.1.1 Conditions: 1/all of them
Before I showed the example condition: selection_1 OR selection_2 OR selection_3
.
This could actually be written in a simpler way…
detection:
selection_1:
Image|endswith: '/bash'
CommandLine|contains:
- DumpCreds
- invoke-mimikatz
selection_2:
CommandLine|contains:
- rpc
- token
- crypto
selection_3:
CommandLine|contains:
- bitcoin
condition: 1 of them
To denote at least 1 of the selections (1 of them
) should be true (selection_1 OR selection_2 OR selection_3
). Ultimately, this is the same detection ion logic as the last example.
However, you can also use all of them
to denote all selections should match.
detection:
selection_1:
CommandLine|contains:
- DumpCreds
- invoke-mimikatz
selection_2:
CommandLine|contains:
- rpc
- token
- crypto
selection_3:
CommandLine|contains:
- bitcoin
condition: all of them
In this example, not all selections must match. Written out;
(Image|endswith = '/bash' AND (CommandLine CONTAINS DumpCreds OR CommandLine CONTAINS invoke-mimikatz))
AND
(CommandLine CONTAINS rpc OR CommandLine CONTAINS token OR CommandLine CONTAINS crypto)
AND
(CommandLine CONTAINS bitcoin)
Note, the Sigma docs advise against using 1 of them
or all of them
.
3.2.2.2 Conditions: 1/all of selection
Instead of X of them
you can be more granular and include parts of a selections in the condition (vs. the entire selection). For example;
logsource:
product: windows
service: system
detection:
selection_1:
EventLog: Security
EventID:
- 517
- 1102
selection_2:
EventID: 6416
ClassName: DiskDrive
condition: all of selection_1 and 1 of selection_2
Here the condition defines all of selection_1
must match, but only 1 field in selection_2
should. Written out this reads;
(EventLog = Security AND ( EventID = 517 OR EventID = 1102 ))
AND
(EventID = 6416 OR ClassName = DiskDrive)
Here instead of the default operator behaviour of a selection (to AND each field), the condition logic for selection_2
turns this into an OR.
*
wildcards (i.e. any number of characters) at arbitrary positions in the condition pattern can also be used. For example;
logsource:
product: windows
service: system
detection:
selection_1:
EventLog: Security
EventID:
- 517
- 1102
selection_2:
EventID: 6416
ClassName: DiskDrive
condition: 1 of selection_*
Written literally it is saying 1 item in each selection must match;
( EventLog = Security OR ( EventID = 517 OR EventID = 1102 ))
AND
( EventID = 6416 OR ClassName = DiskDrive )
3.2.3.3 Conditions: Negation with not
Conditions can be especially useful for filtering use-cases which is where the not
operator comes in handy. Take this example;
logsource:
product: windows
service: system
detection:
selection_1:
EventLog: Security
EventID:
- 517
- 1102
selection_2:
EventID: 6416
ClassName: DiskDrive
keywords_filter|contains:
- error
- failure
condition: 1 of selection_* not keywords_filter
The condition is almost identical to the last example, but is now filtering out any events that contain error
OR failure
.
( EventLog = Security OR ( EventID = 517 OR EventID = 1102 ))
AND
( EventID = 6416 OR ClassName = DiskDrive )
AND NOT
( <the event contains the string 'error' OR 'failure' >
A side not on filtering events using other techniques
Filtering techniques are often common across multiple rules (e.g. the keyword error
used in the last rule is common in all kinds of logs). Instead of writing this filter into every rule, you can use Sigma Filter rules so that the convertors apply them across multiple rules in one command.
Sigma Filter rules are another type of Sigma rule; meta rules.
Sigma Filters closely resemble core Sigma rules in their structure, but use the filter
keyword in place of detection
.
For example win_filter_domain_admins.yml
;
title: Filter Out Domain Controllers
description: Filter out events from Domain Controllers
logsource:
product: windows
filter:
rules:
- files_added_to_an_archive_using_rar_exe
- login_on_jump_host
selection:
ComputerName|startswith: "DC-"
condition: not selection
This filter should be added to the following rules by the convertor;
files_added_to_an_archive_using_rar_exe.yml
(rule)login_on_jump_host.yml
(rule)
Lets work this through using another example.
Here’s the Sigma filter win_filter_admins.yml
;
title: Filter Out Administrator accounts
description: Filters out administrator accounts that start with adm_
logsource:
category: process_creation
product: windows
filter:
rules:
- proc_creation_win_sc_create_service
selection:
User|startswith: "adm_"
condition: not selection
And the core Sigma rule listed in the filter rule;
title: New Service Creation Using Sc.EXE
name: proc_creation_win_sc_create_service
description: Detects the creation of a new service using the "sc.exe" utility.
author: Timur Zinniatullin, Daniil Yugoslavskiy, oscd.community
logsource:
category: process_creation
product: windows
detection:
selection:
Image|endswith: '\sc.exe'
CommandLine|contains|all:
- "create"
- "binPath"
condition: selection
falsepositives:
- Legitimate administrator or user creates a service for legitimate reasons.
- Software installation
level: low
In the example above, the win_filter_admins.yml
Sigma filter is applied to the proc_creation_win_sc_create_service.yml
Sigma rule. The filter will exclude any events where the User field starts with adm_
.
If you wanted to apply this filter to other rules in the future, you could just add that rule to the rules
attribute in the Sigma Filter.
3.2.4.4 Conditions: Using Parenthesis
Parenthesis can be used to add more complex logic to the expression. The part of the condition in parenthesis will be considered first. For example;
As condition
s need to become more complex, using brackets (parenthesis) can offer additional options to the other Condition options specified.
detection:
keywords_1:
- DumpCreds
- invoke-mimikatz
keywords_2:
- rpc
- token
- crypto
keywords_3:
- bitcoin
condition: (keywords_1 and keywords_2) or (keywords_2 and keywords_3)
In this example, if 1 value from keywords_1 and keywords_2
OR 1 value from keywords_2 and keywords_3
is seen in the same event it will trigger a detection.
Bracket are considered with the highest order of operation by downstream Sigma tooling.
3.2.3 Dealing with false positive detections
Once you deploy a rule to one of your security tools analysts will also start to discover some incorrect detections.
You can try to avoid false positive detections by tuning the rule to ignore known erroneous triggers using a filter, for example…
detection:
selection:
- 'rm /var/log/syslog'
- 'rm -r /var/log/syslog'
- 'rm -f /var/log/syslog'
- 'rm -rf /var/log/syslog'
- 'mv /var/log/syslog'
- ' >/var/log/syslog'
- ' > /var/log/syslog'
false_positives:
- '/syslog.'
condition: selection and not false_positives
However, it’s not always possible to account for all reasons false positives occur.
This is where the informational falsepositive
property can be used to describe a list of known false positives which can occur from a detection.
detection:
selection:
- 'rm /var/log/syslog'
- 'rm -r /var/log/syslog'
- 'rm -f /var/log/syslog'
- 'rm -rf /var/log/syslog'
- 'mv /var/log/syslog'
- ' >/var/log/syslog'
- ' > /var/log/syslog'
false_positives:
- '/syslog.'
condition: selection and not false_positives
falsepositives:
- PIM (Privileged Identity Management) generates this event each time 'eligible role' is enabled.
- Legitimate administration activities
This doesn’t affect the detection. However, when the rule is triggered, the falsepositives
information inside the rule can help an analyst triaging alerts as to how they proceed (or if they follow up on it at all).
3.2.4 Dealing with detections
When a rule is deployed, it is only a matter of time before it triggers a detection. When that happens, the analyst handling the detection event might want to start a deeper investigation.
The fields
property inside a Sigma Rule can help an analyst decide the next steps by defining a log fields that could be interesting in further analysis of the event.
detection:
selection:
- 'rm /var/log/syslog'
- 'rm -r /var/log/syslog'
- 'rm -f /var/log/syslog'
- 'rm -rf /var/log/syslog'
- 'mv /var/log/syslog'
- ' >/var/log/syslog'
- ' > /var/log/syslog'
false_positives:
- '/syslog.'
condition: selection and not false_positives
falsepositives:
- PIM (Privileged Identity Management) generates this event each time 'eligible role' is enabled.
- Legitimate administration activities
fields:
- CommandLine
- ParentCommandLine
4. Some Examples
If you’re like me, it is much more helpful to learn from real-world examples.
The Sigma project maintains a body of public rules in the core Sigma repository here. These are very useful starting point when trying to structure a report (and to see if any rules closely match your hypothesis).
4.1 Example 1
Studying this rule that detects CACTUSTORCH activity;
title: HackTool - CACTUSTORCH Remote Thread Creation
id: 2e4e488a-6164-4811-9ea1-f960c7359c40
status: test
description: Detects remote thread creation from CACTUSTORCH as described in references.
references:
- https://twitter.com/SBousseaden/status/1090588499517079552 # Deleted
- https://github.com/mdsecactivebreach/CACTUSTORCH
author: '@SBousseaden (detection), Thomas Patzke (rule)'
date: 2019-02-01
modified: 2023-05-05
tags:
- attack.defense-evasion
- attack.execution
- attack.t1055.012
- attack.t1059.005
- attack.t1059.007
- attack.t1218.005
logsource:
product: windows
category: create_remote_thread
detection:
selection:
SourceImage|endswith:
- '\System32\cscript.exe'
- '\System32\wscript.exe'
- '\System32\mshta.exe'
- '\winword.exe'
- '\excel.exe'
TargetImage|contains: '\SysWOW64\'
StartModule: null
condition: selection
falsepositives:
- Unknown
level: high
This rule should be applied to Windows product logs that can create remote threads (this is a standard Sigma logsource grouping).
The logic can be described literally as:
- the
SourceImage
field in the event must end with\System32\cscript.exe
OR\System32\wscript.exe
OR\System32\mshta.exe
OR\winword.exe
OR\excel.exe
AND - the
TargetImage
field in the event must contain\SysWOW64\
AND - the
StartModule
field must not be in the event
You can also see this rule has been tagged with ATT&CK Tactics and Techniques.
4.2 Example 2
title: Cicada3301 Ransomware Execution via PSExec
id: 79495647-d84d-4804-9a52-5263cfdf2c63
status: experimental
description: |
Detects the use of a potentially-renamed psexec to run the Cicada3301 ransomware tool.
references:
- https://engage.morphisec.com/threat-analysis-cicada3301
author: 'Micah Babinski, Based on Morphisec report by Michael Gorelik (@smgoreli)'
date: 2024-09-08
tags:
- attack.execution
- attack.t1569
- attack.t1569.002
- attack.s0029
logsource:
category: process_creation
product: windows
detection:
selection_1:
- Image|endswith: '\psexec0.exe'
- OriginalFileName: 'psexec.c'
selection_2:
CommandLine|contains:
- '--key'
- '--path'
- '-p '
- '-s '
- '--no_local'
- '--no_net'
- '--no_impl'
- '--no_notes'
filter:
Image|endswith: '\psexec.exe'
condition: all of selection_1 and selection_2 and not filter
falsepositives:
- Unknown
level: high
This rule should be applied to Windows product logs that can create processes (again, this is a standard Sigma logsource grouping).
The logic can be described literally as:
- the
Image
field must end with\psexec0.exe
and have theOriginalFileName
value aspsexec.c
AND - the
CommandLine
field must contain one of the field values forCommandLine
listed inselection_2
(e.g.--key
) AND - the
Image
field must NOT end with\psexec.exe
In summary
This post has given you enough to get started authoring your own basic Sigma detections.
To really make use of what I’ve covered, start putting it into practice.
Define some hypotheses and try and write Sigma detections for them.
SIEM Rules
Your detection engineering AI assistant. Turn cyber threat intelligence research into highly-tuned detection rules.
Discuss this post
Head on over to the dogesec community to discuss this post.
Never miss an update
Sign up to receive new articles in your inbox as they published.