Deconstructing STIX Patterns to write effective detection rules.
STIX 2.1 Indicator Domain Objects are often confused with Indicators of Compromise (IOCs).
STIX Indicator Objects can contain zero or more IOCs, but they are not IOCs themselves.
IOCs are atomic indicators. These are elements or fragments of data that cannot be broken down any further like a hostname, IP address, email address, file name, etc.
In the STIX 2.1 specification, Oasis define Indicator Objects like so:
Indicators contain a pattern that can be used to detect suspicious or malicious cyber activity.
Here is an example of a STIX 2.1 Indicator Object for a known malicious filename.
{
"type": "indicator",
"spec_version": "2.1",
"id": "indicator--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"created": "2016-04-06T20:03:48.000Z",
"modified": "2016-04-06T20:03:48.000Z",
"indicator_types": ["malicious-activity"],
"name": "Some Malware",
"description": "Some malware description",
"pattern": "[ipv4-addr:value='198.51.100.3' AND domain:value='example.com']",
"pattern_type": "stix",
"valid_from": "2016-01-01T00:00:00Z"
}
The Indicator Object contains a filename defined by a STIX Pattern, frp_0.34.3_windows_amd64.zip
. In this example, the filename is an atomic indicator (an IOC).
The indicator is defined in the pattern
field.
The type of pattern allowed (defined in the pattern_type
field) are stix, snort, and yara (see the pattern-type-ov
field).
STIX Patterns (like snort and yara) are very useful in detecting threats. If you’re new to STIX Patterns, this post aims to provide a brief introduction to them.
STIX Indicator Pattern Basics
Firstly, a brief overview of STIX Patterning:
The STIX Patterning language enables the detection of activity on networks and endpoints
STIX Patterns are composed of multiple building blocks, ranging from simple key-value comparisons to more complex, context-sensitive expressions.
Comparison Expressions and Operators
Comparison Expressions are the fundamental building blocks of STIX patterns.
They take an Object Path (using STIX Cyber-observable Objects) and Object Value with a Comparison Operator to evaluate their relationship.
If you missed last weeks post, it talks about STIX Cyber-Observable Objects (SCOs) in more detail that will help you understand how Object Paths are formulated.
Multiple Comparison Expressions can joined by Comparison Expression Operators to create an Obervation Expression.
My earlier example of a filename showed a simple Comparison Expression in a Pattern.
Here is an example of a simple Comparison Expression to detect an IPv4 address:
[ipv4-addr:value='198.51.100.1']
It uses the IPv4 Address Object (ipv4-addr
) and its ID Contributing Property (value
) as the Object path. The Object value is 198.51.100.1
.
Another example, using a Windows Registry Key;
[windows-registry-key:key='HKEY_LOCAL_MACHINE\\System\\Foo\\Bar']
Here I use Windows Registry Key Object Key and its ID Contributing Property (key
). The Object value is HKEY_LOCAL_MACHINE\\System\\Foo\\Bar
.
You can use a range Comparison Operators
in addition to equals (=
). Does not equal (!=
), is greater than (>
), is less than or equal to (>=
), etc.
[directory:path LIKE 'C:\\Windows\\%\\foo']
In the above example I am using the LIKE
Comparison Operator. You’ll notice it is possible to pass capture groups. In the example above %
catches 0 or more characters).
As such a pattern would match (be true) if C:\\Windows\\DAVID\\foo
, C:\\Windows\\JAMES\\foo
, etc. was analysed.
Observation Expressions, Operators and Qualifiers
More than one Comparion Expression can be joined using a Comparison Expression Operator to create an Observation Expression.
The entire Obervation Expression is captured in square brackets []
.
For example, a pattern to match match on either 198.51.100.1/32
or 203.0.113.33/32
could be expressed with the OR
Comparison Expression Operator;
[ipv4-addr:value='198.51.100.1/32' OR ipv4-addr:value='203.0.113.33/32']
Changing the Comparison Expression Operator to an AND
makes the pattern match on both 198.51.100.1/32
and 203.0.113.33/32
;
[ipv4-addr:value='198.51.100.1/32' AND ipv4-addr:value='203.0.113.33/32'
Observation Expressions can also be joinged using Observation Operators.
In the following example there are two Observation Expressions joined by the Observation Operator FOLLOWEDBY
;
[ipv4-addr:value='198.51.100.1/32'] FOLLOWEDBY [ipv4-addr:value='203.0.113.33/32']
The FOLLOWEDBY
Observation Operator defines the order in which Comparison Expressions must match. In this case 198.51.100.1/32
must be followed by 203.0.113.33/32
. Put another way, 198.51.100.1/32
must be detected before 203.0.113.33/32
.
Observation Expression Qualifiers allow for even more definition at the end of a pattern.
You can define WITHIN
, START
/ STOP
, and REPEATS
Observation Expression Qualifiers.
The following example requires the two Observation Expressions to repeat 5 times in order for a match;
([ipv4-addr:value='198.51.100.1/32'] FOLLOWEDBY [ipv4-addr:value='203.0.113.33/32']) REPEATS 5 TIMES
Here is another example that is very similar to a pattern used for malware detection;
([file:hashes.'SHA-256'='ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb'] AND [win-registry-key:key='hkey']) WITHIN 120 SECONDS
Here if the file hash Observation Expression and a Windows Registry Observation Expression are true within 120 seconds of each other then the pattern matches.
Precedence and Parenthesis
Operator Precedence is an important consideration to keep in mind when writing Patterns.
Consider the following Pattern:
[ipv4-addr:value='198.51.100.1/32'] FOLLOWEDBY ([ipv4-addr:value='203.0.113.33/32'] REPEATS 5 TIMES)
Here, the first Observation Expression requires a match on an ipv4-addr:value
equal to 198.51.100.1/32
that precedes 5 occurrences of the Observation Expression where ipv4-addr:value
equal to 203.0.113.33/32
.
Now consider the following Pattern (almost identical to before, but notice the parentheses):
([ipv4-addr:value='198.51.100.1/32'] FOLLOWEDBY [ipv4-addr:value='203.0.113.33/32']) REPEATS 5 TIMES
The first Observation Expression requires a match on an ipv4-addr:value
equal to 198.51.100.1/32
followed by a match on the second Observation Expression for an ipv4-addr:value
equal to 203.0.113.33/32
, this must be seen 5 times for a match.
Helpful tools
The STIX 2 Pattern Validator from Oasis is a great tool in checking your patterns are written correctly.
Simply run the STIX 2 Pattern Validator script with your Pattern. If the Pattern is valid it will return something similar to the following;
$ validate-patterns
Enter a pattern to validate: [file-object:hashes.md5 = '79054025255fb1a26e4bc422aef54eb4']
PASS: [file-object:hashes.md5 = '79054025255fb1a26e4bc422aef54eb4']
If you’re trying to see if content (for example, a log file) matches an existing STIX Pattern you can use the CTI Pattern Matcher.
The next post will be example, so start revising now!
Join the Signals Corps on Discord
Join our public community of intelligence analysts and researchers sharing new content hourly.
Obstracts

Turn any blog into structured threat intelligence.
Stixify

Extract machine readable intelligence from unstructured data.
Vulmatch

Know when software you use is vulnerable, how it is being exploited, and how to detect an attack.
SIEM Rules

View, modify, and deploy SIEM rules for threat hunting.