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='' AND domain:value='']",
    "pattern_type": "stix",
    "valid_from": "2016-01-01T00:00:00Z"

The Indicator Object contains a filename defined by a STIX Pattern, 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

In a bit more detail:

STIX Patterns are composed of multiple building blocks, ranging from simple key-value comparisons to more complex, context-sensitive expressions.

STIX Patterns

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:


It uses the IPv4 Address Object (ipv4-addr) and its ID Contributing Property (value) as the Object path. The Object value is

Another example, using a Windows Registry Key;


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 or could be expressed with the OR Comparison Expression Operator;

[ipv4-addr:value='' OR ipv4-addr:value='']

Changing the Comparison Expression Operator to an AND makes the pattern match on both and;

[ipv4-addr:value='' AND ipv4-addr:value=''

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=''] FOLLOWEDBY [ipv4-addr:value='']

The FOLLOWEDBY Observation Operator defines the order in which Comparison Expressions must match. In this case must be followed by Put another way, must be detected before

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=''] FOLLOWEDBY [ipv4-addr:value='']) 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=''] FOLLOWEDBY ([ipv4-addr:value=''] REPEATS 5 TIMES)

Here, the first Observation Expression requires a match on an ipv4-addr:value equal to that precedes 5 occurrences of the Observation Expression where ipv4-addr:value equal to

Now consider the following Pattern (almost identical to before, but notice the parentheses):

([ipv4-addr:value=''] FOLLOWEDBY [ipv4-addr:value='']) REPEATS 5 TIMES

The first Observation Expression requires a match on an ipv4-addr:value equal to followed by a match on the second Observation Expression for an ipv4-addr:value equal to, 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.



Turn any blog into structured threat intelligence.


Stixify. Extract machine readable intelligence from unstructured data.

Extract machine readable intelligence from unstructured data.



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

SIEM Rules

SIEM Rules. Your detection engineering database.

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